1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * evalfunc.c: Builtin functions 12 */ 13 #define USING_FLOAT_STUFF 14 15 #include "vim.h" 16 17 #if defined(FEAT_EVAL) || defined(PROTO) 18 19 #ifdef VMS 20 # include <float.h> 21 #endif 22 23 #ifdef FEAT_FLOAT 24 static void f_abs(typval_T *argvars, typval_T *rettv); 25 static void f_acos(typval_T *argvars, typval_T *rettv); 26 #endif 27 static void f_and(typval_T *argvars, typval_T *rettv); 28 #ifdef FEAT_FLOAT 29 static void f_asin(typval_T *argvars, typval_T *rettv); 30 static void f_atan(typval_T *argvars, typval_T *rettv); 31 static void f_atan2(typval_T *argvars, typval_T *rettv); 32 #endif 33 #ifdef FEAT_BEVAL 34 static void f_balloon_gettext(typval_T *argvars, typval_T *rettv); 35 static void f_balloon_show(typval_T *argvars, typval_T *rettv); 36 # if defined(FEAT_BEVAL_TERM) 37 static void f_balloon_split(typval_T *argvars, typval_T *rettv); 38 # endif 39 #endif 40 static void f_byte2line(typval_T *argvars, typval_T *rettv); 41 static void byteidx(typval_T *argvars, typval_T *rettv, int comp); 42 static void f_byteidx(typval_T *argvars, typval_T *rettv); 43 static void f_byteidxcomp(typval_T *argvars, typval_T *rettv); 44 static void f_call(typval_T *argvars, typval_T *rettv); 45 #ifdef FEAT_FLOAT 46 static void f_ceil(typval_T *argvars, typval_T *rettv); 47 #endif 48 static void f_changenr(typval_T *argvars, typval_T *rettv); 49 static void f_char2nr(typval_T *argvars, typval_T *rettv); 50 static void f_col(typval_T *argvars, typval_T *rettv); 51 static void f_confirm(typval_T *argvars, typval_T *rettv); 52 static void f_copy(typval_T *argvars, typval_T *rettv); 53 #ifdef FEAT_FLOAT 54 static void f_cos(typval_T *argvars, typval_T *rettv); 55 static void f_cosh(typval_T *argvars, typval_T *rettv); 56 #endif 57 static void f_cursor(typval_T *argsvars, typval_T *rettv); 58 #ifdef MSWIN 59 static void f_debugbreak(typval_T *argvars, typval_T *rettv); 60 #endif 61 static void f_deepcopy(typval_T *argvars, typval_T *rettv); 62 static void f_did_filetype(typval_T *argvars, typval_T *rettv); 63 static void f_echoraw(typval_T *argvars, typval_T *rettv); 64 static void f_empty(typval_T *argvars, typval_T *rettv); 65 static void f_environ(typval_T *argvars, typval_T *rettv); 66 static void f_escape(typval_T *argvars, typval_T *rettv); 67 static void f_eval(typval_T *argvars, typval_T *rettv); 68 static void f_eventhandler(typval_T *argvars, typval_T *rettv); 69 static void f_execute(typval_T *argvars, typval_T *rettv); 70 static void f_exists(typval_T *argvars, typval_T *rettv); 71 #ifdef FEAT_FLOAT 72 static void f_exp(typval_T *argvars, typval_T *rettv); 73 #endif 74 static void f_expand(typval_T *argvars, typval_T *rettv); 75 static void f_expandcmd(typval_T *argvars, typval_T *rettv); 76 static void f_feedkeys(typval_T *argvars, typval_T *rettv); 77 #ifdef FEAT_FLOAT 78 static void f_float2nr(typval_T *argvars, typval_T *rettv); 79 static void f_floor(typval_T *argvars, typval_T *rettv); 80 static void f_fmod(typval_T *argvars, typval_T *rettv); 81 #endif 82 static void f_fnameescape(typval_T *argvars, typval_T *rettv); 83 static void f_foreground(typval_T *argvars, typval_T *rettv); 84 static void f_funcref(typval_T *argvars, typval_T *rettv); 85 static void f_function(typval_T *argvars, typval_T *rettv); 86 static void f_garbagecollect(typval_T *argvars, typval_T *rettv); 87 static void f_get(typval_T *argvars, typval_T *rettv); 88 static void f_getchangelist(typval_T *argvars, typval_T *rettv); 89 static void f_getcharsearch(typval_T *argvars, typval_T *rettv); 90 static void f_getenv(typval_T *argvars, typval_T *rettv); 91 static void f_getfontname(typval_T *argvars, typval_T *rettv); 92 static void f_getjumplist(typval_T *argvars, typval_T *rettv); 93 static void f_getpid(typval_T *argvars, typval_T *rettv); 94 static void f_getcurpos(typval_T *argvars, typval_T *rettv); 95 static void f_getpos(typval_T *argvars, typval_T *rettv); 96 static void f_getreg(typval_T *argvars, typval_T *rettv); 97 static void f_getregtype(typval_T *argvars, typval_T *rettv); 98 static void f_gettagstack(typval_T *argvars, typval_T *rettv); 99 static void f_haslocaldir(typval_T *argvars, typval_T *rettv); 100 static void f_hasmapto(typval_T *argvars, typval_T *rettv); 101 static void f_hlID(typval_T *argvars, typval_T *rettv); 102 static void f_hlexists(typval_T *argvars, typval_T *rettv); 103 static void f_hostname(typval_T *argvars, typval_T *rettv); 104 static void f_iconv(typval_T *argvars, typval_T *rettv); 105 static void f_index(typval_T *argvars, typval_T *rettv); 106 static void f_input(typval_T *argvars, typval_T *rettv); 107 static void f_inputdialog(typval_T *argvars, typval_T *rettv); 108 static void f_inputlist(typval_T *argvars, typval_T *rettv); 109 static void f_inputrestore(typval_T *argvars, typval_T *rettv); 110 static void f_inputsave(typval_T *argvars, typval_T *rettv); 111 static void f_inputsecret(typval_T *argvars, typval_T *rettv); 112 static void f_interrupt(typval_T *argvars, typval_T *rettv); 113 static void f_invert(typval_T *argvars, typval_T *rettv); 114 static void f_islocked(typval_T *argvars, typval_T *rettv); 115 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) 116 static void f_isinf(typval_T *argvars, typval_T *rettv); 117 static void f_isnan(typval_T *argvars, typval_T *rettv); 118 #endif 119 static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv); 120 static void f_len(typval_T *argvars, typval_T *rettv); 121 static void f_libcall(typval_T *argvars, typval_T *rettv); 122 static void f_libcallnr(typval_T *argvars, typval_T *rettv); 123 static void f_line(typval_T *argvars, typval_T *rettv); 124 static void f_line2byte(typval_T *argvars, typval_T *rettv); 125 #ifdef FEAT_FLOAT 126 static void f_log(typval_T *argvars, typval_T *rettv); 127 static void f_log10(typval_T *argvars, typval_T *rettv); 128 #endif 129 #ifdef FEAT_LUA 130 static void f_luaeval(typval_T *argvars, typval_T *rettv); 131 #endif 132 static void f_maparg(typval_T *argvars, typval_T *rettv); 133 static void f_mapcheck(typval_T *argvars, typval_T *rettv); 134 static void f_match(typval_T *argvars, typval_T *rettv); 135 static void f_matchend(typval_T *argvars, typval_T *rettv); 136 static void f_matchlist(typval_T *argvars, typval_T *rettv); 137 static void f_matchstr(typval_T *argvars, typval_T *rettv); 138 static void f_matchstrpos(typval_T *argvars, typval_T *rettv); 139 static void f_max(typval_T *argvars, typval_T *rettv); 140 static void f_min(typval_T *argvars, typval_T *rettv); 141 #ifdef FEAT_MZSCHEME 142 static void f_mzeval(typval_T *argvars, typval_T *rettv); 143 #endif 144 static void f_nextnonblank(typval_T *argvars, typval_T *rettv); 145 static void f_nr2char(typval_T *argvars, typval_T *rettv); 146 static void f_or(typval_T *argvars, typval_T *rettv); 147 #ifdef FEAT_PERL 148 static void f_perleval(typval_T *argvars, typval_T *rettv); 149 #endif 150 #ifdef FEAT_FLOAT 151 static void f_pow(typval_T *argvars, typval_T *rettv); 152 #endif 153 static void f_prevnonblank(typval_T *argvars, typval_T *rettv); 154 static void f_printf(typval_T *argvars, typval_T *rettv); 155 static void f_pum_getpos(typval_T *argvars, typval_T *rettv); 156 static void f_pumvisible(typval_T *argvars, typval_T *rettv); 157 #ifdef FEAT_PYTHON3 158 static void f_py3eval(typval_T *argvars, typval_T *rettv); 159 #endif 160 #ifdef FEAT_PYTHON 161 static void f_pyeval(typval_T *argvars, typval_T *rettv); 162 #endif 163 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) 164 static void f_pyxeval(typval_T *argvars, typval_T *rettv); 165 #endif 166 static void f_test_srand_seed(typval_T *argvars, typval_T *rettv); 167 static void f_rand(typval_T *argvars, typval_T *rettv); 168 static void f_range(typval_T *argvars, typval_T *rettv); 169 static void f_reg_executing(typval_T *argvars, typval_T *rettv); 170 static void f_reg_recording(typval_T *argvars, typval_T *rettv); 171 static void f_rename(typval_T *argvars, typval_T *rettv); 172 static void f_repeat(typval_T *argvars, typval_T *rettv); 173 #ifdef FEAT_FLOAT 174 static void f_round(typval_T *argvars, typval_T *rettv); 175 #endif 176 #ifdef FEAT_RUBY 177 static void f_rubyeval(typval_T *argvars, typval_T *rettv); 178 #endif 179 static void f_screenattr(typval_T *argvars, typval_T *rettv); 180 static void f_screenchar(typval_T *argvars, typval_T *rettv); 181 static void f_screenchars(typval_T *argvars, typval_T *rettv); 182 static void f_screencol(typval_T *argvars, typval_T *rettv); 183 static void f_screenrow(typval_T *argvars, typval_T *rettv); 184 static void f_screenstring(typval_T *argvars, typval_T *rettv); 185 static void f_search(typval_T *argvars, typval_T *rettv); 186 static void f_searchdecl(typval_T *argvars, typval_T *rettv); 187 static void f_searchpair(typval_T *argvars, typval_T *rettv); 188 static void f_searchpairpos(typval_T *argvars, typval_T *rettv); 189 static void f_searchpos(typval_T *argvars, typval_T *rettv); 190 static void f_setcharsearch(typval_T *argvars, typval_T *rettv); 191 static void f_setenv(typval_T *argvars, typval_T *rettv); 192 static void f_setfperm(typval_T *argvars, typval_T *rettv); 193 static void f_setpos(typval_T *argvars, typval_T *rettv); 194 static void f_setreg(typval_T *argvars, typval_T *rettv); 195 static void f_settagstack(typval_T *argvars, typval_T *rettv); 196 #ifdef FEAT_CRYPT 197 static void f_sha256(typval_T *argvars, typval_T *rettv); 198 #endif 199 static void f_shellescape(typval_T *argvars, typval_T *rettv); 200 static void f_shiftwidth(typval_T *argvars, typval_T *rettv); 201 #ifdef FEAT_FLOAT 202 static void f_sin(typval_T *argvars, typval_T *rettv); 203 static void f_sinh(typval_T *argvars, typval_T *rettv); 204 #endif 205 static void f_soundfold(typval_T *argvars, typval_T *rettv); 206 static void f_spellbadword(typval_T *argvars, typval_T *rettv); 207 static void f_spellsuggest(typval_T *argvars, typval_T *rettv); 208 static void f_split(typval_T *argvars, typval_T *rettv); 209 #ifdef FEAT_FLOAT 210 static void f_sqrt(typval_T *argvars, typval_T *rettv); 211 #endif 212 static void f_srand(typval_T *argvars, typval_T *rettv); 213 #ifdef FEAT_FLOAT 214 static void f_str2float(typval_T *argvars, typval_T *rettv); 215 #endif 216 static void f_str2list(typval_T *argvars, typval_T *rettv); 217 static void f_str2nr(typval_T *argvars, typval_T *rettv); 218 static void f_strchars(typval_T *argvars, typval_T *rettv); 219 static void f_strgetchar(typval_T *argvars, typval_T *rettv); 220 static void f_stridx(typval_T *argvars, typval_T *rettv); 221 static void f_strlen(typval_T *argvars, typval_T *rettv); 222 static void f_strcharpart(typval_T *argvars, typval_T *rettv); 223 static void f_strpart(typval_T *argvars, typval_T *rettv); 224 static void f_strridx(typval_T *argvars, typval_T *rettv); 225 static void f_strtrans(typval_T *argvars, typval_T *rettv); 226 static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv); 227 static void f_strwidth(typval_T *argvars, typval_T *rettv); 228 static void f_submatch(typval_T *argvars, typval_T *rettv); 229 static void f_substitute(typval_T *argvars, typval_T *rettv); 230 static void f_swapinfo(typval_T *argvars, typval_T *rettv); 231 static void f_swapname(typval_T *argvars, typval_T *rettv); 232 static void f_synID(typval_T *argvars, typval_T *rettv); 233 static void f_synIDattr(typval_T *argvars, typval_T *rettv); 234 static void f_synIDtrans(typval_T *argvars, typval_T *rettv); 235 static void f_synstack(typval_T *argvars, typval_T *rettv); 236 static void f_synconcealed(typval_T *argvars, typval_T *rettv); 237 static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv); 238 static void f_taglist(typval_T *argvars, typval_T *rettv); 239 static void f_tagfiles(typval_T *argvars, typval_T *rettv); 240 #ifdef FEAT_FLOAT 241 static void f_tan(typval_T *argvars, typval_T *rettv); 242 static void f_tanh(typval_T *argvars, typval_T *rettv); 243 #endif 244 static void f_tolower(typval_T *argvars, typval_T *rettv); 245 static void f_toupper(typval_T *argvars, typval_T *rettv); 246 static void f_tr(typval_T *argvars, typval_T *rettv); 247 static void f_trim(typval_T *argvars, typval_T *rettv); 248 #ifdef FEAT_FLOAT 249 static void f_trunc(typval_T *argvars, typval_T *rettv); 250 #endif 251 static void f_type(typval_T *argvars, typval_T *rettv); 252 static void f_virtcol(typval_T *argvars, typval_T *rettv); 253 static void f_visualmode(typval_T *argvars, typval_T *rettv); 254 static void f_wildmenumode(typval_T *argvars, typval_T *rettv); 255 static void f_windowsversion(typval_T *argvars, typval_T *rettv); 256 static void f_wordcount(typval_T *argvars, typval_T *rettv); 257 static void f_xor(typval_T *argvars, typval_T *rettv); 258 259 260 static type_T * 261 ret_void(int argcount UNUSED, type_T **argtypes UNUSED) 262 { 263 return &t_void; 264 } 265 static type_T * 266 ret_any(int argcount UNUSED, type_T **argtypes UNUSED) 267 { 268 return &t_any; 269 } 270 static type_T * 271 ret_number(int argcount UNUSED, type_T **argtypes UNUSED) 272 { 273 return &t_number; 274 } 275 static type_T * 276 ret_float(int argcount UNUSED, type_T **argtypes UNUSED) 277 { 278 return &t_float; 279 } 280 static type_T * 281 ret_string(int argcount UNUSED, type_T **argtypes UNUSED) 282 { 283 return &t_string; 284 } 285 static type_T * 286 ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED) 287 { 288 return &t_list_any; 289 } 290 static type_T * 291 ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED) 292 { 293 return &t_list_number; 294 } 295 static type_T * 296 ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED) 297 { 298 return &t_list_string; 299 } 300 static type_T * 301 ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED) 302 { 303 return &t_list_dict_any; 304 } 305 static type_T * 306 ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED) 307 { 308 return &t_dict_any; 309 } 310 static type_T * 311 ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED) 312 { 313 return &t_dict_number; 314 } 315 static type_T * 316 ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED) 317 { 318 return &t_dict_string; 319 } 320 static type_T * 321 ret_blob(int argcount UNUSED, type_T **argtypes UNUSED) 322 { 323 return &t_blob; 324 } 325 static type_T * 326 ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED) 327 { 328 return &t_func_any; 329 } 330 static type_T * 331 ret_channel(int argcount UNUSED, type_T **argtypes UNUSED) 332 { 333 return &t_channel; 334 } 335 static type_T * 336 ret_job(int argcount UNUSED, type_T **argtypes UNUSED) 337 { 338 return &t_job; 339 } 340 341 static type_T *ret_f_function(int argcount, type_T **argtypes); 342 343 /* 344 * Array with names and number of arguments of all internal functions 345 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH! 346 */ 347 typedef struct 348 { 349 char *f_name; // function name 350 char f_min_argc; // minimal number of arguments 351 char f_max_argc; // maximal number of arguments 352 char f_argtype; // for method: FEARG_ values 353 type_T *(*f_retfunc)(int argcount, type_T **argtypes); 354 // return type function 355 void (*f_func)(typval_T *args, typval_T *rvar); 356 // implementation of function 357 } funcentry_T; 358 359 // values for f_argtype; zero means it cannot be used as a method 360 #define FEARG_1 1 // base is the first argument 361 #define FEARG_2 2 // base is the second argument 362 #define FEARG_3 3 // base is the third argument 363 #define FEARG_4 4 // base is the fourth argument 364 #define FEARG_LAST 9 // base is the last argument 365 366 #ifdef FEAT_FLOAT 367 # define FLOAT_FUNC(name) name 368 #else 369 # define FLOAT_FUNC(name) NULL 370 #endif 371 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) 372 # define MATH_FUNC(name) name 373 #else 374 # define MATH_FUNC(name) NULL 375 #endif 376 #ifdef FEAT_TIMERS 377 # define TIMER_FUNC(name) name 378 #else 379 # define TIMER_FUNC(name) NULL 380 #endif 381 #ifdef FEAT_JOB_CHANNEL 382 # define JOB_FUNC(name) name 383 #else 384 # define JOB_FUNC(name) NULL 385 #endif 386 #ifdef FEAT_PROP_POPUP 387 # define PROP_FUNC(name) name 388 #else 389 # define PROP_FUNC(name) NULL 390 #endif 391 #ifdef FEAT_SIGNS 392 # define SIGN_FUNC(name) name 393 #else 394 # define SIGN_FUNC(name) NULL 395 #endif 396 #ifdef FEAT_SOUND 397 # define SOUND_FUNC(name) name 398 #else 399 # define SOUND_FUNC(name) NULL 400 #endif 401 #ifdef FEAT_TERMINAL 402 # define TERM_FUNC(name) name 403 #else 404 # define TERM_FUNC(name) NULL 405 #endif 406 407 static funcentry_T global_functions[] = 408 { 409 {"abs", 1, 1, FEARG_1, ret_any, FLOAT_FUNC(f_abs)}, 410 {"acos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_acos)}, 411 {"add", 2, 2, FEARG_1, ret_any, f_add}, 412 {"and", 2, 2, FEARG_1, ret_number, f_and}, 413 {"append", 2, 2, FEARG_LAST, ret_number, f_append}, 414 {"appendbufline", 3, 3, FEARG_LAST, ret_number, f_appendbufline}, 415 {"argc", 0, 1, 0, ret_number, f_argc}, 416 {"argidx", 0, 0, 0, ret_number, f_argidx}, 417 {"arglistid", 0, 2, 0, ret_number, f_arglistid}, 418 {"argv", 0, 2, 0, ret_any, f_argv}, 419 {"asin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_asin)}, 420 {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps}, 421 {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal}, 422 {"assert_equalfile", 2, 2, FEARG_1, ret_number, f_assert_equalfile}, 423 {"assert_exception", 1, 2, 0, ret_number, f_assert_exception}, 424 {"assert_fails", 1, 3, FEARG_1, ret_number, f_assert_fails}, 425 {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false}, 426 {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange}, 427 {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match}, 428 {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal}, 429 {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch}, 430 {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report}, 431 {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true}, 432 {"atan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_atan)}, 433 {"atan2", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_atan2)}, 434 {"balloon_gettext", 0, 0, 0, ret_string, 435 #ifdef FEAT_BEVAL 436 f_balloon_gettext 437 #else 438 NULL 439 #endif 440 }, 441 {"balloon_show", 1, 1, FEARG_1, ret_void, 442 #ifdef FEAT_BEVAL 443 f_balloon_show 444 #else 445 NULL 446 #endif 447 }, 448 {"balloon_split", 1, 1, FEARG_1, ret_list_string, 449 #if defined(FEAT_BEVAL_TERM) 450 f_balloon_split 451 #else 452 NULL 453 #endif 454 }, 455 {"browse", 4, 4, 0, ret_string, f_browse}, 456 {"browsedir", 2, 2, 0, ret_string, f_browsedir}, 457 {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd}, 458 {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists}, 459 {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete 460 {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete 461 {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete 462 {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted}, 463 {"bufload", 1, 1, FEARG_1, ret_void, f_bufload}, 464 {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded}, 465 {"bufname", 0, 1, FEARG_1, ret_string, f_bufname}, 466 {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr}, 467 {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid}, 468 {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr}, 469 {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line}, 470 {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx}, 471 {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp}, 472 {"call", 2, 3, FEARG_1, ret_any, f_call}, 473 {"ceil", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_ceil)}, 474 {"ch_canread", 1, 1, FEARG_1, ret_number, JOB_FUNC(f_ch_canread)}, 475 {"ch_close", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close)}, 476 {"ch_close_in", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close_in)}, 477 {"ch_evalexpr", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalexpr)}, 478 {"ch_evalraw", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalraw)}, 479 {"ch_getbufnr", 2, 2, FEARG_1, ret_number, JOB_FUNC(f_ch_getbufnr)}, 480 {"ch_getjob", 1, 1, FEARG_1, ret_job, JOB_FUNC(f_ch_getjob)}, 481 {"ch_info", 1, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_ch_info)}, 482 {"ch_log", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_log)}, 483 {"ch_logfile", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_logfile)}, 484 {"ch_open", 1, 2, FEARG_1, ret_channel, JOB_FUNC(f_ch_open)}, 485 {"ch_read", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_read)}, 486 {"ch_readblob", 1, 2, FEARG_1, ret_blob, JOB_FUNC(f_ch_readblob)}, 487 {"ch_readraw", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_readraw)}, 488 {"ch_sendexpr", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendexpr)}, 489 {"ch_sendraw", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendraw)}, 490 {"ch_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_setoptions)}, 491 {"ch_status", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_status)}, 492 {"changenr", 0, 0, 0, ret_number, f_changenr}, 493 {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr}, 494 {"chdir", 1, 1, FEARG_1, ret_string, f_chdir}, 495 {"cindent", 1, 1, FEARG_1, ret_number, f_cindent}, 496 {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches}, 497 {"col", 1, 1, FEARG_1, ret_number, f_col}, 498 {"complete", 2, 2, FEARG_2, ret_void, f_complete}, 499 {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add}, 500 {"complete_check", 0, 0, 0, ret_number, f_complete_check}, 501 {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info}, 502 {"confirm", 1, 4, FEARG_1, ret_number, f_confirm}, 503 {"copy", 1, 1, FEARG_1, ret_any, f_copy}, 504 {"cos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cos)}, 505 {"cosh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cosh)}, 506 {"count", 2, 4, FEARG_1, ret_number, f_count}, 507 {"cscope_connection",0,3, 0, ret_number, f_cscope_connection}, 508 {"cursor", 1, 3, FEARG_1, ret_number, f_cursor}, 509 {"debugbreak", 1, 1, FEARG_1, ret_number, 510 #ifdef MSWIN 511 f_debugbreak 512 #else 513 NULL 514 #endif 515 }, 516 {"deepcopy", 1, 2, FEARG_1, ret_any, f_deepcopy}, 517 {"delete", 1, 2, FEARG_1, ret_number, f_delete}, 518 {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline}, 519 {"did_filetype", 0, 0, 0, ret_number, f_did_filetype}, 520 {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler}, 521 {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID}, 522 {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw}, 523 {"empty", 1, 1, FEARG_1, ret_number, f_empty}, 524 {"environ", 0, 0, 0, ret_dict_string, f_environ}, 525 {"escape", 2, 2, FEARG_1, ret_string, f_escape}, 526 {"eval", 1, 1, FEARG_1, ret_any, f_eval}, 527 {"eventhandler", 0, 0, 0, ret_number, f_eventhandler}, 528 {"executable", 1, 1, FEARG_1, ret_number, f_executable}, 529 {"execute", 1, 2, FEARG_1, ret_string, f_execute}, 530 {"exepath", 1, 1, FEARG_1, ret_string, f_exepath}, 531 {"exists", 1, 1, FEARG_1, ret_number, f_exists}, 532 {"exp", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_exp)}, 533 {"expand", 1, 3, FEARG_1, ret_any, f_expand}, 534 {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd}, 535 {"extend", 2, 3, FEARG_1, ret_any, f_extend}, 536 {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys}, 537 {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete 538 {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable}, 539 {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable}, 540 {"filter", 2, 2, FEARG_1, ret_any, f_filter}, 541 {"finddir", 1, 3, FEARG_1, ret_string, f_finddir}, 542 {"findfile", 1, 3, FEARG_1, ret_string, f_findfile}, 543 {"float2nr", 1, 1, FEARG_1, ret_number, FLOAT_FUNC(f_float2nr)}, 544 {"floor", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_floor)}, 545 {"fmod", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_fmod)}, 546 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape}, 547 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify}, 548 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed}, 549 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend}, 550 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel}, 551 {"foldtext", 0, 0, 0, ret_string, f_foldtext}, 552 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult}, 553 {"foreground", 0, 0, 0, ret_void, f_foreground}, 554 {"funcref", 1, 3, FEARG_1, ret_func_any, f_funcref}, 555 {"function", 1, 3, FEARG_1, ret_f_function, f_function}, 556 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect}, 557 {"get", 2, 3, FEARG_1, ret_any, f_get}, 558 {"getbufinfo", 0, 1, 0, ret_list_dict_any, f_getbufinfo}, 559 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline}, 560 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar}, 561 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist}, 562 {"getchar", 0, 1, 0, ret_number, f_getchar}, 563 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod}, 564 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch}, 565 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline}, 566 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos}, 567 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype}, 568 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype}, 569 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion}, 570 {"getcurpos", 0, 0, 0, ret_list_number, f_getcurpos}, 571 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd}, 572 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv}, 573 {"getfontname", 0, 1, 0, ret_string, f_getfontname}, 574 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm}, 575 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize}, 576 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime}, 577 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype}, 578 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus}, 579 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist}, 580 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline}, 581 {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist}, 582 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches}, 583 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos}, 584 {"getpid", 0, 0, 0, ret_number, f_getpid}, 585 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos}, 586 {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist}, 587 {"getreg", 0, 3, FEARG_1, ret_string, f_getreg}, 588 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype}, 589 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo}, 590 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar}, 591 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar}, 592 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack}, 593 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo}, 594 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos}, 595 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx}, 596 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy}, 597 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar}, 598 {"glob", 1, 4, FEARG_1, ret_any, f_glob}, 599 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat}, 600 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath}, 601 {"has", 1, 2, 0, ret_number, f_has}, 602 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key}, 603 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir}, 604 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto}, 605 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete 606 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete 607 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd}, 608 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel}, 609 {"histget", 1, 2, FEARG_1, ret_string, f_histget}, 610 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr}, 611 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID}, 612 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists}, 613 {"hostname", 0, 0, 0, ret_string, f_hostname}, 614 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv}, 615 {"indent", 1, 1, FEARG_1, ret_number, f_indent}, 616 {"index", 2, 4, FEARG_1, ret_number, f_index}, 617 {"input", 1, 3, FEARG_1, ret_string, f_input}, 618 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog}, 619 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist}, 620 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore}, 621 {"inputsave", 0, 0, 0, ret_number, f_inputsave}, 622 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret}, 623 {"insert", 2, 3, FEARG_1, ret_any, f_insert}, 624 {"interrupt", 0, 0, 0, ret_void, f_interrupt}, 625 {"invert", 1, 1, FEARG_1, ret_number, f_invert}, 626 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory}, 627 {"isinf", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isinf)}, 628 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked}, 629 {"isnan", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isnan)}, 630 {"items", 1, 1, FEARG_1, ret_list_any, f_items}, 631 {"job_getchannel", 1, 1, FEARG_1, ret_channel, JOB_FUNC(f_job_getchannel)}, 632 {"job_info", 0, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_job_info)}, 633 {"job_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_job_setoptions)}, 634 {"job_start", 1, 2, FEARG_1, ret_job, JOB_FUNC(f_job_start)}, 635 {"job_status", 1, 1, FEARG_1, ret_string, JOB_FUNC(f_job_status)}, 636 {"job_stop", 1, 2, FEARG_1, ret_number, JOB_FUNC(f_job_stop)}, 637 {"join", 1, 2, FEARG_1, ret_string, f_join}, 638 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode}, 639 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode}, 640 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode}, 641 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode}, 642 {"keys", 1, 1, FEARG_1, ret_list_any, f_keys}, 643 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete 644 {"len", 1, 1, FEARG_1, ret_number, f_len}, 645 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall}, 646 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr}, 647 {"line", 1, 2, FEARG_1, ret_number, f_line}, 648 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte}, 649 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent}, 650 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str}, 651 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add}, 652 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush}, 653 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove}, 654 {"localtime", 0, 0, 0, ret_number, f_localtime}, 655 {"log", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log)}, 656 {"log10", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log10)}, 657 {"luaeval", 1, 2, FEARG_1, ret_any, 658 #ifdef FEAT_LUA 659 f_luaeval 660 #else 661 NULL 662 #endif 663 }, 664 {"map", 2, 2, FEARG_1, ret_any, f_map}, 665 {"maparg", 1, 4, FEARG_1, ret_string, f_maparg}, 666 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck}, 667 {"match", 2, 4, FEARG_1, ret_any, f_match}, 668 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd}, 669 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos}, 670 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg}, 671 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete}, 672 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend}, 673 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist}, 674 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr}, 675 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos}, 676 {"max", 1, 1, FEARG_1, ret_any, f_max}, 677 {"menu_info", 1, 2, FEARG_1, ret_dict_any, 678 #ifdef FEAT_MENU 679 f_menu_info 680 #else 681 NULL 682 #endif 683 }, 684 {"min", 1, 1, FEARG_1, ret_any, f_min}, 685 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir}, 686 {"mode", 0, 1, FEARG_1, ret_string, f_mode}, 687 {"mzeval", 1, 1, FEARG_1, ret_any, 688 #ifdef FEAT_MZSCHEME 689 f_mzeval 690 #else 691 NULL 692 #endif 693 }, 694 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank}, 695 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char}, 696 {"or", 2, 2, FEARG_1, ret_number, f_or}, 697 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten}, 698 {"perleval", 1, 1, FEARG_1, ret_any, 699 #ifdef FEAT_PERL 700 f_perleval 701 #else 702 NULL 703 #endif 704 }, 705 {"popup_atcursor", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_atcursor)}, 706 {"popup_beval", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_beval)}, 707 {"popup_clear", 0, 1, 0, ret_void, PROP_FUNC(f_popup_clear)}, 708 {"popup_close", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_close)}, 709 {"popup_create", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_create)}, 710 {"popup_dialog", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_dialog)}, 711 {"popup_filter_menu", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_menu)}, 712 {"popup_filter_yesno", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_yesno)}, 713 {"popup_findinfo", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findinfo)}, 714 {"popup_findpreview", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findpreview)}, 715 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getoptions)}, 716 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getpos)}, 717 {"popup_hide", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_hide)}, 718 {"popup_list", 0, 0, 0, ret_list_number, PROP_FUNC(f_popup_list)}, 719 {"popup_locate", 2, 2, 0, ret_number, PROP_FUNC(f_popup_locate)}, 720 {"popup_menu", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_menu)}, 721 {"popup_move", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_move)}, 722 {"popup_notification", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_notification)}, 723 {"popup_setoptions", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_setoptions)}, 724 {"popup_settext", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_settext)}, 725 {"popup_show", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_show)}, 726 {"pow", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_pow)}, 727 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank}, 728 {"printf", 1, 19, FEARG_2, ret_string, f_printf}, 729 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setcallback)}, 730 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, JOB_FUNC(f_prompt_setinterrupt)}, 731 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setprompt)}, 732 {"prop_add", 3, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_add)}, 733 {"prop_clear", 1, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_clear)}, 734 {"prop_find", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_find)}, 735 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, PROP_FUNC(f_prop_list)}, 736 {"prop_remove", 1, 3, FEARG_1, ret_number, PROP_FUNC(f_prop_remove)}, 737 {"prop_type_add", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_add)}, 738 {"prop_type_change", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_change)}, 739 {"prop_type_delete", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_delete)}, 740 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_type_get)}, 741 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, PROP_FUNC(f_prop_type_list)}, 742 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos}, 743 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible}, 744 {"py3eval", 1, 1, FEARG_1, ret_any, 745 #ifdef FEAT_PYTHON3 746 f_py3eval 747 #else 748 NULL 749 #endif 750 }, 751 {"pyeval", 1, 1, FEARG_1, ret_any, 752 #ifdef FEAT_PYTHON 753 f_pyeval 754 #else 755 NULL 756 #endif 757 }, 758 {"pyxeval", 1, 1, FEARG_1, ret_any, 759 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) 760 f_pyxeval 761 #else 762 NULL 763 #endif 764 }, 765 {"rand", 0, 1, FEARG_1, ret_number, f_rand}, 766 {"range", 1, 3, FEARG_1, ret_list_number, f_range}, 767 {"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir}, 768 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile}, 769 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing}, 770 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording}, 771 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime}, 772 {"reltimefloat", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_reltimefloat)}, 773 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr}, 774 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr}, 775 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground}, 776 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek}, 777 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read}, 778 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send}, 779 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver}, 780 {"remove", 2, 3, FEARG_1, ret_any, f_remove}, 781 {"rename", 2, 2, FEARG_1, ret_number, f_rename}, 782 {"repeat", 2, 2, FEARG_1, ret_any, f_repeat}, 783 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve}, 784 {"reverse", 1, 1, FEARG_1, ret_any, f_reverse}, 785 {"round", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_round)}, 786 {"rubyeval", 1, 1, FEARG_1, ret_any, 787 #ifdef FEAT_RUBY 788 f_rubyeval 789 #else 790 NULL 791 #endif 792 }, 793 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr}, 794 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar}, 795 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars}, 796 {"screencol", 0, 0, 0, ret_number, f_screencol}, 797 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos}, 798 {"screenrow", 0, 0, 0, ret_number, f_screenrow}, 799 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring}, 800 {"search", 1, 4, FEARG_1, ret_number, f_search}, 801 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl}, 802 {"searchpair", 3, 7, 0, ret_number, f_searchpair}, 803 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos}, 804 {"searchpos", 1, 4, FEARG_1, ret_list_number, f_searchpos}, 805 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client}, 806 {"serverlist", 0, 0, 0, ret_string, f_serverlist}, 807 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline}, 808 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar}, 809 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch}, 810 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos}, 811 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv}, 812 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm}, 813 {"setline", 2, 2, FEARG_2, ret_number, f_setline}, 814 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist}, 815 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches}, 816 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos}, 817 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist}, 818 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg}, 819 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar}, 820 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar}, 821 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack}, 822 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar}, 823 {"sha256", 1, 1, FEARG_1, ret_string, 824 #ifdef FEAT_CRYPT 825 f_sha256 826 #else 827 NULL 828 #endif 829 }, 830 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape}, 831 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth}, 832 {"sign_define", 1, 2, FEARG_1, ret_any, SIGN_FUNC(f_sign_define)}, 833 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)}, 834 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)}, 835 {"sign_jump", 3, 3, FEARG_1, ret_number, SIGN_FUNC(f_sign_jump)}, 836 {"sign_place", 4, 5, FEARG_1, ret_number, SIGN_FUNC(f_sign_place)}, 837 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_placelist)}, 838 {"sign_undefine", 0, 1, FEARG_1, ret_number, SIGN_FUNC(f_sign_undefine)}, 839 {"sign_unplace", 1, 2, FEARG_1, ret_number, SIGN_FUNC(f_sign_unplace)}, 840 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_unplacelist)}, 841 {"simplify", 1, 1, FEARG_1, ret_string, f_simplify}, 842 {"sin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sin)}, 843 {"sinh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sinh)}, 844 {"sort", 1, 3, FEARG_1, ret_list_any, f_sort}, 845 {"sound_clear", 0, 0, 0, ret_void, SOUND_FUNC(f_sound_clear)}, 846 {"sound_playevent", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playevent)}, 847 {"sound_playfile", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playfile)}, 848 {"sound_stop", 1, 1, FEARG_1, ret_void, SOUND_FUNC(f_sound_stop)}, 849 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold}, 850 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword}, 851 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest}, 852 {"split", 1, 3, FEARG_1, ret_list_string, f_split}, 853 {"sqrt", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sqrt)}, 854 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand}, 855 {"state", 0, 1, FEARG_1, ret_string, f_state}, 856 {"str2float", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_str2float)}, 857 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list}, 858 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr}, 859 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart}, 860 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars}, 861 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth}, 862 {"strftime", 1, 2, FEARG_1, ret_string, 863 #ifdef HAVE_STRFTIME 864 f_strftime 865 #else 866 NULL 867 #endif 868 }, 869 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar}, 870 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx}, 871 {"string", 1, 1, FEARG_1, ret_string, f_string}, 872 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen}, 873 {"strpart", 2, 3, FEARG_1, ret_string, f_strpart}, 874 {"strptime", 2, 2, FEARG_1, ret_number, 875 #ifdef HAVE_STRPTIME 876 f_strptime 877 #else 878 NULL 879 #endif 880 }, 881 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx}, 882 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans}, 883 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth}, 884 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch}, 885 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute}, 886 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo}, 887 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname}, 888 {"synID", 3, 3, 0, ret_number, f_synID}, 889 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr}, 890 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans}, 891 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed}, 892 {"synstack", 2, 2, 0, ret_list_number, f_synstack}, 893 {"system", 1, 2, FEARG_1, ret_string, f_system}, 894 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist}, 895 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist}, 896 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr}, 897 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr}, 898 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles}, 899 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist}, 900 {"tan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tan)}, 901 {"tanh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tanh)}, 902 {"tempname", 0, 0, 0, ret_string, f_tempname}, 903 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, TERM_FUNC(f_term_dumpdiff)}, 904 {"term_dumpload", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_dumpload)}, 905 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, TERM_FUNC(f_term_dumpwrite)}, 906 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getaltscreen)}, 907 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string, 908 #if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)) 909 f_term_getansicolors 910 #else 911 NULL 912 #endif 913 }, 914 {"term_getattr", 2, 2, FEARG_1, ret_number, TERM_FUNC(f_term_getattr)}, 915 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, TERM_FUNC(f_term_getcursor)}, 916 {"term_getjob", 1, 1, FEARG_1, ret_job, TERM_FUNC(f_term_getjob)}, 917 {"term_getline", 2, 2, FEARG_1, ret_string, TERM_FUNC(f_term_getline)}, 918 {"term_getscrolled", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getscrolled)}, 919 {"term_getsize", 1, 1, FEARG_1, ret_list_number, TERM_FUNC(f_term_getsize)}, 920 {"term_getstatus", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_getstatus)}, 921 {"term_gettitle", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_gettitle)}, 922 {"term_gettty", 1, 2, FEARG_1, ret_string, TERM_FUNC(f_term_gettty)}, 923 {"term_list", 0, 0, 0, ret_list_number, TERM_FUNC(f_term_list)}, 924 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, TERM_FUNC(f_term_scrape)}, 925 {"term_sendkeys", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_sendkeys)}, 926 {"term_setansicolors", 2, 2, FEARG_1, ret_void, 927 #if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)) 928 f_term_setansicolors 929 #else 930 NULL 931 #endif 932 }, 933 {"term_setapi", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setapi)}, 934 {"term_setkill", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setkill)}, 935 {"term_setrestore", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setrestore)}, 936 {"term_setsize", 3, 3, FEARG_1, ret_void, TERM_FUNC(f_term_setsize)}, 937 {"term_start", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_start)}, 938 {"term_wait", 1, 2, FEARG_1, ret_void, TERM_FUNC(f_term_wait)}, 939 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail}, 940 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir}, 941 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput}, 942 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now}, 943 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon}, 944 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue}, 945 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error}, 946 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob}, 947 {"test_null_channel", 0, 0, 0, ret_channel, JOB_FUNC(f_test_null_channel)}, 948 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict}, 949 {"test_null_function", 0, 0, 0, ret_func_any, f_test_null_function}, 950 {"test_null_job", 0, 0, 0, ret_job, JOB_FUNC(f_test_null_job)}, 951 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list}, 952 {"test_null_partial", 0, 0, 0, ret_func_any, f_test_null_partial}, 953 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string}, 954 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set}, 955 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override}, 956 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount}, 957 {"test_scrollbar", 3, 3, FEARG_2, ret_void, 958 #ifdef FEAT_GUI 959 f_test_scrollbar 960 #else 961 NULL 962 #endif 963 }, 964 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse}, 965 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime}, 966 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed}, 967 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown}, 968 {"test_void", 0, 0, 0, ret_any, f_test_void}, 969 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, TIMER_FUNC(f_timer_info)}, 970 {"timer_pause", 2, 2, FEARG_1, ret_void, TIMER_FUNC(f_timer_pause)}, 971 {"timer_start", 2, 3, FEARG_1, ret_number, TIMER_FUNC(f_timer_start)}, 972 {"timer_stop", 1, 1, FEARG_1, ret_void, TIMER_FUNC(f_timer_stop)}, 973 {"timer_stopall", 0, 0, 0, ret_void, TIMER_FUNC(f_timer_stopall)}, 974 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower}, 975 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper}, 976 {"tr", 3, 3, FEARG_1, ret_string, f_tr}, 977 {"trim", 1, 2, FEARG_1, ret_string, f_trim}, 978 {"trunc", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_trunc)}, 979 {"type", 1, 1, FEARG_1, ret_number, f_type}, 980 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile}, 981 {"undotree", 0, 0, 0, ret_dict_any, f_undotree}, 982 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq}, 983 {"values", 1, 1, FEARG_1, ret_list_any, f_values}, 984 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol}, 985 {"visualmode", 0, 1, 0, ret_string, f_visualmode}, 986 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode}, 987 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute}, 988 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf}, 989 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid}, 990 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype}, 991 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid}, 992 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin}, 993 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win}, 994 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos}, 995 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove}, 996 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr}, 997 {"wincol", 0, 0, 0, ret_number, f_wincol}, 998 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion}, 999 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight}, 1000 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout}, 1001 {"winline", 0, 0, 0, ret_number, f_winline}, 1002 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr}, 1003 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd}, 1004 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview}, 1005 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview}, 1006 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth}, 1007 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount}, 1008 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile}, 1009 {"xor", 2, 2, FEARG_1, ret_number, f_xor}, 1010 }; 1011 1012 /* 1013 * Function given to ExpandGeneric() to obtain the list of internal 1014 * or user defined function names. 1015 */ 1016 char_u * 1017 get_function_name(expand_T *xp, int idx) 1018 { 1019 static int intidx = -1; 1020 char_u *name; 1021 1022 if (idx == 0) 1023 intidx = -1; 1024 if (intidx < 0) 1025 { 1026 name = get_user_func_name(xp, idx); 1027 if (name != NULL) 1028 return name; 1029 } 1030 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T))) 1031 { 1032 STRCPY(IObuff, global_functions[intidx].f_name); 1033 STRCAT(IObuff, "("); 1034 if (global_functions[intidx].f_max_argc == 0) 1035 STRCAT(IObuff, ")"); 1036 return IObuff; 1037 } 1038 1039 return NULL; 1040 } 1041 1042 /* 1043 * Function given to ExpandGeneric() to obtain the list of internal or 1044 * user defined variable or function names. 1045 */ 1046 char_u * 1047 get_expr_name(expand_T *xp, int idx) 1048 { 1049 static int intidx = -1; 1050 char_u *name; 1051 1052 if (idx == 0) 1053 intidx = -1; 1054 if (intidx < 0) 1055 { 1056 name = get_function_name(xp, idx); 1057 if (name != NULL) 1058 return name; 1059 } 1060 return get_user_var_name(xp, ++intidx); 1061 } 1062 1063 /* 1064 * Find internal function "name" in table "global_functions". 1065 * Return index, or -1 if not found or "implemented" is TRUE and the function 1066 * is not implemented. 1067 */ 1068 static int 1069 find_internal_func_opt(char_u *name, int implemented) 1070 { 1071 int first = 0; 1072 int last; 1073 int cmp; 1074 int x; 1075 1076 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1; 1077 1078 // Find the function name in the table. Binary search. 1079 while (first <= last) 1080 { 1081 x = first + ((unsigned)(last - first) >> 1); 1082 cmp = STRCMP(name, global_functions[x].f_name); 1083 if (cmp < 0) 1084 last = x - 1; 1085 else if (cmp > 0) 1086 first = x + 1; 1087 else if (implemented && global_functions[x].f_func == NULL) 1088 break; 1089 else 1090 return x; 1091 } 1092 return -1; 1093 } 1094 1095 /* 1096 * Find internal function "name" in table "global_functions". 1097 * Return index, or -1 if not found or the function is not implemented. 1098 */ 1099 int 1100 find_internal_func(char_u *name) 1101 { 1102 return find_internal_func_opt(name, TRUE); 1103 } 1104 1105 int 1106 has_internal_func(char_u *name) 1107 { 1108 return find_internal_func_opt(name, TRUE) >= 0; 1109 } 1110 1111 static int 1112 has_internal_func_name(char_u *name) 1113 { 1114 return find_internal_func_opt(name, FALSE) >= 0; 1115 } 1116 1117 char * 1118 internal_func_name(int idx) 1119 { 1120 return global_functions[idx].f_name; 1121 } 1122 1123 type_T * 1124 internal_func_ret_type(int idx, int argcount, type_T **argtypes) 1125 { 1126 return global_functions[idx].f_retfunc(argcount, argtypes); 1127 } 1128 1129 /* 1130 * Check the argument count to use for internal function "idx". 1131 * Returns OK or FAIL; 1132 */ 1133 int 1134 check_internal_func(int idx, int argcount) 1135 { 1136 int res; 1137 char *name; 1138 1139 if (argcount < global_functions[idx].f_min_argc) 1140 res = FCERR_TOOFEW; 1141 else if (argcount > global_functions[idx].f_max_argc) 1142 res = FCERR_TOOMANY; 1143 else 1144 return OK; 1145 1146 name = internal_func_name(idx); 1147 if (res == FCERR_TOOMANY) 1148 semsg(_(e_toomanyarg), name); 1149 else 1150 semsg(_(e_toofewarg), name); 1151 return FAIL; 1152 } 1153 1154 int 1155 call_internal_func( 1156 char_u *name, 1157 int argcount, 1158 typval_T *argvars, 1159 typval_T *rettv) 1160 { 1161 int i; 1162 1163 i = find_internal_func(name); 1164 if (i < 0) 1165 return FCERR_UNKNOWN; 1166 if (argcount < global_functions[i].f_min_argc) 1167 return FCERR_TOOFEW; 1168 if (argcount > global_functions[i].f_max_argc) 1169 return FCERR_TOOMANY; 1170 argvars[argcount].v_type = VAR_UNKNOWN; 1171 global_functions[i].f_func(argvars, rettv); 1172 return FCERR_NONE; 1173 } 1174 1175 void 1176 call_internal_func_by_idx( 1177 int idx, 1178 typval_T *argvars, 1179 typval_T *rettv) 1180 { 1181 global_functions[idx].f_func(argvars, rettv); 1182 } 1183 1184 /* 1185 * Invoke a method for base->method(). 1186 */ 1187 int 1188 call_internal_method( 1189 char_u *name, 1190 int argcount, 1191 typval_T *argvars, 1192 typval_T *rettv, 1193 typval_T *basetv) 1194 { 1195 int i; 1196 int fi; 1197 typval_T argv[MAX_FUNC_ARGS + 1]; 1198 1199 fi = find_internal_func(name); 1200 if (fi < 0) 1201 return FCERR_UNKNOWN; 1202 if (global_functions[fi].f_argtype == 0) 1203 return FCERR_NOTMETHOD; 1204 if (argcount + 1 < global_functions[fi].f_min_argc) 1205 return FCERR_TOOFEW; 1206 if (argcount + 1 > global_functions[fi].f_max_argc) 1207 return FCERR_TOOMANY; 1208 1209 if (global_functions[fi].f_argtype == FEARG_LAST) 1210 { 1211 // base value goes last 1212 for (i = 0; i < argcount; ++i) 1213 argv[i] = argvars[i]; 1214 argv[argcount] = *basetv; 1215 } 1216 else if (global_functions[fi].f_argtype == FEARG_2) 1217 { 1218 // base value goes second 1219 argv[0] = argvars[0]; 1220 argv[1] = *basetv; 1221 for (i = 1; i < argcount; ++i) 1222 argv[i + 1] = argvars[i]; 1223 } 1224 else if (global_functions[fi].f_argtype == FEARG_3) 1225 { 1226 // base value goes third 1227 argv[0] = argvars[0]; 1228 argv[1] = argvars[1]; 1229 argv[2] = *basetv; 1230 for (i = 2; i < argcount; ++i) 1231 argv[i + 1] = argvars[i]; 1232 } 1233 else if (global_functions[fi].f_argtype == FEARG_4) 1234 { 1235 // base value goes fourth 1236 argv[0] = argvars[0]; 1237 argv[1] = argvars[1]; 1238 argv[2] = argvars[2]; 1239 argv[3] = *basetv; 1240 for (i = 3; i < argcount; ++i) 1241 argv[i + 1] = argvars[i]; 1242 } 1243 else 1244 { 1245 // FEARG_1: base value goes first 1246 argv[0] = *basetv; 1247 for (i = 0; i < argcount; ++i) 1248 argv[i + 1] = argvars[i]; 1249 } 1250 argv[argcount + 1].v_type = VAR_UNKNOWN; 1251 1252 global_functions[fi].f_func(argv, rettv); 1253 return FCERR_NONE; 1254 } 1255 1256 /* 1257 * Return TRUE for a non-zero Number and a non-empty String. 1258 */ 1259 int 1260 non_zero_arg(typval_T *argvars) 1261 { 1262 return ((argvars[0].v_type == VAR_NUMBER 1263 && argvars[0].vval.v_number != 0) 1264 || (argvars[0].v_type == VAR_BOOL 1265 && argvars[0].vval.v_number == VVAL_TRUE) 1266 || (argvars[0].v_type == VAR_STRING 1267 && argvars[0].vval.v_string != NULL 1268 && *argvars[0].vval.v_string != NUL)); 1269 } 1270 1271 /* 1272 * Get the lnum from the first argument. 1273 * Also accepts ".", "$", etc., but that only works for the current buffer. 1274 * Returns -1 on error. 1275 */ 1276 linenr_T 1277 tv_get_lnum(typval_T *argvars) 1278 { 1279 linenr_T lnum; 1280 1281 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL); 1282 if (lnum == 0) // no valid number, try using arg like line() 1283 { 1284 int fnum; 1285 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum); 1286 1287 if (fp != NULL) 1288 lnum = fp->lnum; 1289 } 1290 return lnum; 1291 } 1292 1293 /* 1294 * Get the lnum from the first argument. 1295 * Also accepts "$", then "buf" is used. 1296 * Returns 0 on error. 1297 */ 1298 linenr_T 1299 tv_get_lnum_buf(typval_T *argvars, buf_T *buf) 1300 { 1301 if (argvars[0].v_type == VAR_STRING 1302 && argvars[0].vval.v_string != NULL 1303 && argvars[0].vval.v_string[0] == '$' 1304 && buf != NULL) 1305 return buf->b_ml.ml_line_count; 1306 return (linenr_T)tv_get_number_chk(&argvars[0], NULL); 1307 } 1308 1309 #ifdef FEAT_FLOAT 1310 /* 1311 * Get the float value of "argvars[0]" into "f". 1312 * Returns FAIL when the argument is not a Number or Float. 1313 */ 1314 static int 1315 get_float_arg(typval_T *argvars, float_T *f) 1316 { 1317 if (argvars[0].v_type == VAR_FLOAT) 1318 { 1319 *f = argvars[0].vval.v_float; 1320 return OK; 1321 } 1322 if (argvars[0].v_type == VAR_NUMBER) 1323 { 1324 *f = (float_T)argvars[0].vval.v_number; 1325 return OK; 1326 } 1327 emsg(_("E808: Number or Float required")); 1328 return FAIL; 1329 } 1330 1331 /* 1332 * "abs(expr)" function 1333 */ 1334 static void 1335 f_abs(typval_T *argvars, typval_T *rettv) 1336 { 1337 if (argvars[0].v_type == VAR_FLOAT) 1338 { 1339 rettv->v_type = VAR_FLOAT; 1340 rettv->vval.v_float = fabs(argvars[0].vval.v_float); 1341 } 1342 else 1343 { 1344 varnumber_T n; 1345 int error = FALSE; 1346 1347 n = tv_get_number_chk(&argvars[0], &error); 1348 if (error) 1349 rettv->vval.v_number = -1; 1350 else if (n > 0) 1351 rettv->vval.v_number = n; 1352 else 1353 rettv->vval.v_number = -n; 1354 } 1355 } 1356 1357 /* 1358 * "acos()" function 1359 */ 1360 static void 1361 f_acos(typval_T *argvars, typval_T *rettv) 1362 { 1363 float_T f = 0.0; 1364 1365 rettv->v_type = VAR_FLOAT; 1366 if (get_float_arg(argvars, &f) == OK) 1367 rettv->vval.v_float = acos(f); 1368 else 1369 rettv->vval.v_float = 0.0; 1370 } 1371 #endif 1372 1373 /* 1374 * "and(expr, expr)" function 1375 */ 1376 static void 1377 f_and(typval_T *argvars, typval_T *rettv) 1378 { 1379 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL) 1380 & tv_get_number_chk(&argvars[1], NULL); 1381 } 1382 1383 #ifdef FEAT_FLOAT 1384 /* 1385 * "asin()" function 1386 */ 1387 static void 1388 f_asin(typval_T *argvars, typval_T *rettv) 1389 { 1390 float_T f = 0.0; 1391 1392 rettv->v_type = VAR_FLOAT; 1393 if (get_float_arg(argvars, &f) == OK) 1394 rettv->vval.v_float = asin(f); 1395 else 1396 rettv->vval.v_float = 0.0; 1397 } 1398 1399 /* 1400 * "atan()" function 1401 */ 1402 static void 1403 f_atan(typval_T *argvars, typval_T *rettv) 1404 { 1405 float_T f = 0.0; 1406 1407 rettv->v_type = VAR_FLOAT; 1408 if (get_float_arg(argvars, &f) == OK) 1409 rettv->vval.v_float = atan(f); 1410 else 1411 rettv->vval.v_float = 0.0; 1412 } 1413 1414 /* 1415 * "atan2()" function 1416 */ 1417 static void 1418 f_atan2(typval_T *argvars, typval_T *rettv) 1419 { 1420 float_T fx = 0.0, fy = 0.0; 1421 1422 rettv->v_type = VAR_FLOAT; 1423 if (get_float_arg(argvars, &fx) == OK 1424 && get_float_arg(&argvars[1], &fy) == OK) 1425 rettv->vval.v_float = atan2(fx, fy); 1426 else 1427 rettv->vval.v_float = 0.0; 1428 } 1429 #endif 1430 1431 /* 1432 * "balloon_show()" function 1433 */ 1434 #ifdef FEAT_BEVAL 1435 static void 1436 f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv) 1437 { 1438 rettv->v_type = VAR_STRING; 1439 if (balloonEval != NULL) 1440 { 1441 if (balloonEval->msg == NULL) 1442 rettv->vval.v_string = NULL; 1443 else 1444 rettv->vval.v_string = vim_strsave(balloonEval->msg); 1445 } 1446 } 1447 1448 static void 1449 f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED) 1450 { 1451 if (balloonEval != NULL) 1452 { 1453 if (argvars[0].v_type == VAR_LIST 1454 # ifdef FEAT_GUI 1455 && !gui.in_use 1456 # endif 1457 ) 1458 { 1459 list_T *l = argvars[0].vval.v_list; 1460 1461 // empty list removes the balloon 1462 post_balloon(balloonEval, NULL, 1463 l == NULL || l->lv_len == 0 ? NULL : l); 1464 } 1465 else 1466 { 1467 char_u *mesg = tv_get_string_chk(&argvars[0]); 1468 1469 if (mesg != NULL) 1470 // empty string removes the balloon 1471 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL); 1472 } 1473 } 1474 } 1475 1476 # if defined(FEAT_BEVAL_TERM) 1477 static void 1478 f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED) 1479 { 1480 if (rettv_list_alloc(rettv) == OK) 1481 { 1482 char_u *msg = tv_get_string_chk(&argvars[0]); 1483 1484 if (msg != NULL) 1485 { 1486 pumitem_T *array; 1487 int size = split_message(msg, &array); 1488 int i; 1489 1490 // Skip the first and last item, they are always empty. 1491 for (i = 1; i < size - 1; ++i) 1492 list_append_string(rettv->vval.v_list, array[i].pum_text, -1); 1493 while (size > 0) 1494 vim_free(array[--size].pum_text); 1495 vim_free(array); 1496 } 1497 } 1498 } 1499 # endif 1500 #endif 1501 1502 /* 1503 * Get buffer by number or pattern. 1504 */ 1505 buf_T * 1506 tv_get_buf(typval_T *tv, int curtab_only) 1507 { 1508 char_u *name = tv->vval.v_string; 1509 buf_T *buf; 1510 1511 if (tv->v_type == VAR_NUMBER) 1512 return buflist_findnr((int)tv->vval.v_number); 1513 if (tv->v_type != VAR_STRING) 1514 return NULL; 1515 if (name == NULL || *name == NUL) 1516 return curbuf; 1517 if (name[0] == '$' && name[1] == NUL) 1518 return lastbuf; 1519 1520 buf = buflist_find_by_name(name, curtab_only); 1521 1522 // If not found, try expanding the name, like done for bufexists(). 1523 if (buf == NULL) 1524 buf = find_buffer(tv); 1525 1526 return buf; 1527 } 1528 1529 /* 1530 * Get the buffer from "arg" and give an error and return NULL if it is not 1531 * valid. 1532 */ 1533 buf_T * 1534 get_buf_arg(typval_T *arg) 1535 { 1536 buf_T *buf; 1537 1538 ++emsg_off; 1539 buf = tv_get_buf(arg, FALSE); 1540 --emsg_off; 1541 if (buf == NULL) 1542 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg)); 1543 return buf; 1544 } 1545 1546 /* 1547 * "byte2line(byte)" function 1548 */ 1549 static void 1550 f_byte2line(typval_T *argvars UNUSED, typval_T *rettv) 1551 { 1552 #ifndef FEAT_BYTEOFF 1553 rettv->vval.v_number = -1; 1554 #else 1555 long boff = 0; 1556 1557 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error 1558 if (boff < 0) 1559 rettv->vval.v_number = -1; 1560 else 1561 rettv->vval.v_number = ml_find_line_or_offset(curbuf, 1562 (linenr_T)0, &boff); 1563 #endif 1564 } 1565 1566 static void 1567 byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED) 1568 { 1569 char_u *t; 1570 char_u *str; 1571 varnumber_T idx; 1572 1573 str = tv_get_string_chk(&argvars[0]); 1574 idx = tv_get_number_chk(&argvars[1], NULL); 1575 rettv->vval.v_number = -1; 1576 if (str == NULL || idx < 0) 1577 return; 1578 1579 t = str; 1580 for ( ; idx > 0; idx--) 1581 { 1582 if (*t == NUL) // EOL reached 1583 return; 1584 if (enc_utf8 && comp) 1585 t += utf_ptr2len(t); 1586 else 1587 t += (*mb_ptr2len)(t); 1588 } 1589 rettv->vval.v_number = (varnumber_T)(t - str); 1590 } 1591 1592 /* 1593 * "byteidx()" function 1594 */ 1595 static void 1596 f_byteidx(typval_T *argvars, typval_T *rettv) 1597 { 1598 byteidx(argvars, rettv, FALSE); 1599 } 1600 1601 /* 1602 * "byteidxcomp()" function 1603 */ 1604 static void 1605 f_byteidxcomp(typval_T *argvars, typval_T *rettv) 1606 { 1607 byteidx(argvars, rettv, TRUE); 1608 } 1609 1610 /* 1611 * "call(func, arglist [, dict])" function 1612 */ 1613 static void 1614 f_call(typval_T *argvars, typval_T *rettv) 1615 { 1616 char_u *func; 1617 partial_T *partial = NULL; 1618 dict_T *selfdict = NULL; 1619 1620 if (argvars[1].v_type != VAR_LIST) 1621 { 1622 emsg(_(e_listreq)); 1623 return; 1624 } 1625 if (argvars[1].vval.v_list == NULL) 1626 return; 1627 1628 if (argvars[0].v_type == VAR_FUNC) 1629 func = argvars[0].vval.v_string; 1630 else if (argvars[0].v_type == VAR_PARTIAL) 1631 { 1632 partial = argvars[0].vval.v_partial; 1633 func = partial_name(partial); 1634 } 1635 else 1636 func = tv_get_string(&argvars[0]); 1637 if (*func == NUL) 1638 return; // type error or empty name 1639 1640 if (argvars[2].v_type != VAR_UNKNOWN) 1641 { 1642 if (argvars[2].v_type != VAR_DICT) 1643 { 1644 emsg(_(e_dictreq)); 1645 return; 1646 } 1647 selfdict = argvars[2].vval.v_dict; 1648 } 1649 1650 (void)func_call(func, &argvars[1], partial, selfdict, rettv); 1651 } 1652 1653 #ifdef FEAT_FLOAT 1654 /* 1655 * "ceil({float})" function 1656 */ 1657 static void 1658 f_ceil(typval_T *argvars, typval_T *rettv) 1659 { 1660 float_T f = 0.0; 1661 1662 rettv->v_type = VAR_FLOAT; 1663 if (get_float_arg(argvars, &f) == OK) 1664 rettv->vval.v_float = ceil(f); 1665 else 1666 rettv->vval.v_float = 0.0; 1667 } 1668 #endif 1669 1670 /* 1671 * "changenr()" function 1672 */ 1673 static void 1674 f_changenr(typval_T *argvars UNUSED, typval_T *rettv) 1675 { 1676 rettv->vval.v_number = curbuf->b_u_seq_cur; 1677 } 1678 1679 /* 1680 * "char2nr(string)" function 1681 */ 1682 static void 1683 f_char2nr(typval_T *argvars, typval_T *rettv) 1684 { 1685 if (has_mbyte) 1686 { 1687 int utf8 = 0; 1688 1689 if (argvars[1].v_type != VAR_UNKNOWN) 1690 utf8 = (int)tv_get_number_chk(&argvars[1], NULL); 1691 1692 if (utf8) 1693 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0])); 1694 else 1695 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0])); 1696 } 1697 else 1698 rettv->vval.v_number = tv_get_string(&argvars[0])[0]; 1699 } 1700 1701 win_T * 1702 get_optional_window(typval_T *argvars, int idx) 1703 { 1704 win_T *win = curwin; 1705 1706 if (argvars[idx].v_type != VAR_UNKNOWN) 1707 { 1708 win = find_win_by_nr_or_id(&argvars[idx]); 1709 if (win == NULL) 1710 { 1711 emsg(_(e_invalwindow)); 1712 return NULL; 1713 } 1714 } 1715 return win; 1716 } 1717 1718 /* 1719 * "col(string)" function 1720 */ 1721 static void 1722 f_col(typval_T *argvars, typval_T *rettv) 1723 { 1724 colnr_T col = 0; 1725 pos_T *fp; 1726 int fnum = curbuf->b_fnum; 1727 1728 fp = var2fpos(&argvars[0], FALSE, &fnum); 1729 if (fp != NULL && fnum == curbuf->b_fnum) 1730 { 1731 if (fp->col == MAXCOL) 1732 { 1733 // '> can be MAXCOL, get the length of the line then 1734 if (fp->lnum <= curbuf->b_ml.ml_line_count) 1735 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1; 1736 else 1737 col = MAXCOL; 1738 } 1739 else 1740 { 1741 col = fp->col + 1; 1742 // col(".") when the cursor is on the NUL at the end of the line 1743 // because of "coladd" can be seen as an extra column. 1744 if (virtual_active() && fp == &curwin->w_cursor) 1745 { 1746 char_u *p = ml_get_cursor(); 1747 1748 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p, 1749 curwin->w_virtcol - curwin->w_cursor.coladd)) 1750 { 1751 int l; 1752 1753 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL) 1754 col += l; 1755 } 1756 } 1757 } 1758 } 1759 rettv->vval.v_number = col; 1760 } 1761 1762 /* 1763 * "confirm(message, buttons[, default [, type]])" function 1764 */ 1765 static void 1766 f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 1767 { 1768 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 1769 char_u *message; 1770 char_u *buttons = NULL; 1771 char_u buf[NUMBUFLEN]; 1772 char_u buf2[NUMBUFLEN]; 1773 int def = 1; 1774 int type = VIM_GENERIC; 1775 char_u *typestr; 1776 int error = FALSE; 1777 1778 message = tv_get_string_chk(&argvars[0]); 1779 if (message == NULL) 1780 error = TRUE; 1781 if (argvars[1].v_type != VAR_UNKNOWN) 1782 { 1783 buttons = tv_get_string_buf_chk(&argvars[1], buf); 1784 if (buttons == NULL) 1785 error = TRUE; 1786 if (argvars[2].v_type != VAR_UNKNOWN) 1787 { 1788 def = (int)tv_get_number_chk(&argvars[2], &error); 1789 if (argvars[3].v_type != VAR_UNKNOWN) 1790 { 1791 typestr = tv_get_string_buf_chk(&argvars[3], buf2); 1792 if (typestr == NULL) 1793 error = TRUE; 1794 else 1795 { 1796 switch (TOUPPER_ASC(*typestr)) 1797 { 1798 case 'E': type = VIM_ERROR; break; 1799 case 'Q': type = VIM_QUESTION; break; 1800 case 'I': type = VIM_INFO; break; 1801 case 'W': type = VIM_WARNING; break; 1802 case 'G': type = VIM_GENERIC; break; 1803 } 1804 } 1805 } 1806 } 1807 } 1808 1809 if (buttons == NULL || *buttons == NUL) 1810 buttons = (char_u *)_("&Ok"); 1811 1812 if (!error) 1813 rettv->vval.v_number = do_dialog(type, NULL, message, buttons, 1814 def, NULL, FALSE); 1815 #endif 1816 } 1817 1818 /* 1819 * "copy()" function 1820 */ 1821 static void 1822 f_copy(typval_T *argvars, typval_T *rettv) 1823 { 1824 item_copy(&argvars[0], rettv, FALSE, 0); 1825 } 1826 1827 #ifdef FEAT_FLOAT 1828 /* 1829 * "cos()" function 1830 */ 1831 static void 1832 f_cos(typval_T *argvars, typval_T *rettv) 1833 { 1834 float_T f = 0.0; 1835 1836 rettv->v_type = VAR_FLOAT; 1837 if (get_float_arg(argvars, &f) == OK) 1838 rettv->vval.v_float = cos(f); 1839 else 1840 rettv->vval.v_float = 0.0; 1841 } 1842 1843 /* 1844 * "cosh()" function 1845 */ 1846 static void 1847 f_cosh(typval_T *argvars, typval_T *rettv) 1848 { 1849 float_T f = 0.0; 1850 1851 rettv->v_type = VAR_FLOAT; 1852 if (get_float_arg(argvars, &f) == OK) 1853 rettv->vval.v_float = cosh(f); 1854 else 1855 rettv->vval.v_float = 0.0; 1856 } 1857 #endif 1858 1859 /* 1860 * "cursor(lnum, col)" function, or 1861 * "cursor(list)" 1862 * 1863 * Moves the cursor to the specified line and column. 1864 * Returns 0 when the position could be set, -1 otherwise. 1865 */ 1866 static void 1867 f_cursor(typval_T *argvars, typval_T *rettv) 1868 { 1869 long line, col; 1870 long coladd = 0; 1871 int set_curswant = TRUE; 1872 1873 rettv->vval.v_number = -1; 1874 if (argvars[1].v_type == VAR_UNKNOWN) 1875 { 1876 pos_T pos; 1877 colnr_T curswant = -1; 1878 1879 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL) 1880 { 1881 emsg(_(e_invarg)); 1882 return; 1883 } 1884 line = pos.lnum; 1885 col = pos.col; 1886 coladd = pos.coladd; 1887 if (curswant >= 0) 1888 { 1889 curwin->w_curswant = curswant - 1; 1890 set_curswant = FALSE; 1891 } 1892 } 1893 else 1894 { 1895 line = tv_get_lnum(argvars); 1896 col = (long)tv_get_number_chk(&argvars[1], NULL); 1897 if (argvars[2].v_type != VAR_UNKNOWN) 1898 coladd = (long)tv_get_number_chk(&argvars[2], NULL); 1899 } 1900 if (line < 0 || col < 0 || coladd < 0) 1901 return; // type error; errmsg already given 1902 if (line > 0) 1903 curwin->w_cursor.lnum = line; 1904 if (col > 0) 1905 curwin->w_cursor.col = col - 1; 1906 curwin->w_cursor.coladd = coladd; 1907 1908 // Make sure the cursor is in a valid position. 1909 check_cursor(); 1910 // Correct cursor for multi-byte character. 1911 if (has_mbyte) 1912 mb_adjust_cursor(); 1913 1914 curwin->w_set_curswant = set_curswant; 1915 rettv->vval.v_number = 0; 1916 } 1917 1918 #ifdef MSWIN 1919 /* 1920 * "debugbreak()" function 1921 */ 1922 static void 1923 f_debugbreak(typval_T *argvars, typval_T *rettv) 1924 { 1925 int pid; 1926 1927 rettv->vval.v_number = FAIL; 1928 pid = (int)tv_get_number(&argvars[0]); 1929 if (pid == 0) 1930 emsg(_(e_invarg)); 1931 else 1932 { 1933 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid); 1934 1935 if (hProcess != NULL) 1936 { 1937 DebugBreakProcess(hProcess); 1938 CloseHandle(hProcess); 1939 rettv->vval.v_number = OK; 1940 } 1941 } 1942 } 1943 #endif 1944 1945 /* 1946 * "deepcopy()" function 1947 */ 1948 static void 1949 f_deepcopy(typval_T *argvars, typval_T *rettv) 1950 { 1951 int noref = 0; 1952 int copyID; 1953 1954 if (argvars[1].v_type != VAR_UNKNOWN) 1955 noref = (int)tv_get_number_chk(&argvars[1], NULL); 1956 if (noref < 0 || noref > 1) 1957 emsg(_(e_invarg)); 1958 else 1959 { 1960 copyID = get_copyID(); 1961 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0); 1962 } 1963 } 1964 1965 /* 1966 * "did_filetype()" function 1967 */ 1968 static void 1969 f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 1970 { 1971 rettv->vval.v_number = did_filetype; 1972 } 1973 1974 /* 1975 * "echoraw({expr})" function 1976 */ 1977 static void 1978 f_echoraw(typval_T *argvars, typval_T *rettv UNUSED) 1979 { 1980 char_u *str = tv_get_string_chk(&argvars[0]); 1981 1982 if (str != NULL && *str != NUL) 1983 { 1984 out_str(str); 1985 out_flush(); 1986 } 1987 } 1988 1989 /* 1990 * "empty({expr})" function 1991 */ 1992 static void 1993 f_empty(typval_T *argvars, typval_T *rettv) 1994 { 1995 int n = FALSE; 1996 1997 switch (argvars[0].v_type) 1998 { 1999 case VAR_STRING: 2000 case VAR_FUNC: 2001 n = argvars[0].vval.v_string == NULL 2002 || *argvars[0].vval.v_string == NUL; 2003 break; 2004 case VAR_PARTIAL: 2005 n = FALSE; 2006 break; 2007 case VAR_NUMBER: 2008 n = argvars[0].vval.v_number == 0; 2009 break; 2010 case VAR_FLOAT: 2011 #ifdef FEAT_FLOAT 2012 n = argvars[0].vval.v_float == 0.0; 2013 break; 2014 #endif 2015 case VAR_LIST: 2016 n = argvars[0].vval.v_list == NULL 2017 || argvars[0].vval.v_list->lv_len == 0; 2018 break; 2019 case VAR_DICT: 2020 n = argvars[0].vval.v_dict == NULL 2021 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0; 2022 break; 2023 case VAR_BOOL: 2024 case VAR_SPECIAL: 2025 n = argvars[0].vval.v_number != VVAL_TRUE; 2026 break; 2027 2028 case VAR_BLOB: 2029 n = argvars[0].vval.v_blob == NULL 2030 || argvars[0].vval.v_blob->bv_ga.ga_len == 0; 2031 break; 2032 2033 case VAR_JOB: 2034 #ifdef FEAT_JOB_CHANNEL 2035 n = argvars[0].vval.v_job == NULL 2036 || argvars[0].vval.v_job->jv_status != JOB_STARTED; 2037 break; 2038 #endif 2039 case VAR_CHANNEL: 2040 #ifdef FEAT_JOB_CHANNEL 2041 n = argvars[0].vval.v_channel == NULL 2042 || !channel_is_open(argvars[0].vval.v_channel); 2043 break; 2044 #endif 2045 case VAR_UNKNOWN: 2046 case VAR_ANY: 2047 case VAR_VOID: 2048 internal_error_no_abort("f_empty(UNKNOWN)"); 2049 n = TRUE; 2050 break; 2051 } 2052 2053 rettv->vval.v_number = n; 2054 } 2055 2056 /* 2057 * "environ()" function 2058 */ 2059 static void 2060 f_environ(typval_T *argvars UNUSED, typval_T *rettv) 2061 { 2062 #if !defined(AMIGA) 2063 int i = 0; 2064 char_u *entry, *value; 2065 # ifdef MSWIN 2066 extern wchar_t **_wenviron; 2067 # else 2068 extern char **environ; 2069 # endif 2070 2071 if (rettv_dict_alloc(rettv) != OK) 2072 return; 2073 2074 # ifdef MSWIN 2075 if (*_wenviron == NULL) 2076 return; 2077 # else 2078 if (*environ == NULL) 2079 return; 2080 # endif 2081 2082 for (i = 0; ; ++i) 2083 { 2084 # ifdef MSWIN 2085 short_u *p; 2086 2087 if ((p = (short_u *)_wenviron[i]) == NULL) 2088 return; 2089 entry = utf16_to_enc(p, NULL); 2090 # else 2091 if ((entry = (char_u *)environ[i]) == NULL) 2092 return; 2093 entry = vim_strsave(entry); 2094 # endif 2095 if (entry == NULL) // out of memory 2096 return; 2097 if ((value = vim_strchr(entry, '=')) == NULL) 2098 { 2099 vim_free(entry); 2100 continue; 2101 } 2102 *value++ = NUL; 2103 dict_add_string(rettv->vval.v_dict, (char *)entry, value); 2104 vim_free(entry); 2105 } 2106 #endif 2107 } 2108 2109 /* 2110 * "escape({string}, {chars})" function 2111 */ 2112 static void 2113 f_escape(typval_T *argvars, typval_T *rettv) 2114 { 2115 char_u buf[NUMBUFLEN]; 2116 2117 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]), 2118 tv_get_string_buf(&argvars[1], buf)); 2119 rettv->v_type = VAR_STRING; 2120 } 2121 2122 /* 2123 * "eval()" function 2124 */ 2125 static void 2126 f_eval(typval_T *argvars, typval_T *rettv) 2127 { 2128 char_u *s, *p; 2129 2130 s = tv_get_string_chk(&argvars[0]); 2131 if (s != NULL) 2132 s = skipwhite(s); 2133 2134 p = s; 2135 if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL) 2136 { 2137 if (p != NULL && !aborting()) 2138 semsg(_(e_invexpr2), p); 2139 need_clr_eos = FALSE; 2140 rettv->v_type = VAR_NUMBER; 2141 rettv->vval.v_number = 0; 2142 } 2143 else if (*s != NUL) 2144 emsg(_(e_trailing)); 2145 } 2146 2147 /* 2148 * "eventhandler()" function 2149 */ 2150 static void 2151 f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv) 2152 { 2153 rettv->vval.v_number = vgetc_busy || input_busy; 2154 } 2155 2156 static garray_T redir_execute_ga; 2157 2158 /* 2159 * Append "value[value_len]" to the execute() output. 2160 */ 2161 void 2162 execute_redir_str(char_u *value, int value_len) 2163 { 2164 int len; 2165 2166 if (value_len == -1) 2167 len = (int)STRLEN(value); // Append the entire string 2168 else 2169 len = value_len; // Append only "value_len" characters 2170 if (ga_grow(&redir_execute_ga, len) == OK) 2171 { 2172 mch_memmove((char *)redir_execute_ga.ga_data 2173 + redir_execute_ga.ga_len, value, len); 2174 redir_execute_ga.ga_len += len; 2175 } 2176 } 2177 2178 /* 2179 * Get next line from a list. 2180 * Called by do_cmdline() to get the next line. 2181 * Returns allocated string, or NULL for end of function. 2182 */ 2183 2184 static char_u * 2185 get_list_line( 2186 int c UNUSED, 2187 void *cookie, 2188 int indent UNUSED, 2189 int do_concat UNUSED) 2190 { 2191 listitem_T **p = (listitem_T **)cookie; 2192 listitem_T *item = *p; 2193 char_u buf[NUMBUFLEN]; 2194 char_u *s; 2195 2196 if (item == NULL) 2197 return NULL; 2198 s = tv_get_string_buf_chk(&item->li_tv, buf); 2199 *p = item->li_next; 2200 return s == NULL ? NULL : vim_strsave(s); 2201 } 2202 2203 /* 2204 * "execute()" function 2205 */ 2206 void 2207 execute_common(typval_T *argvars, typval_T *rettv, int arg_off) 2208 { 2209 char_u *cmd = NULL; 2210 list_T *list = NULL; 2211 int save_msg_silent = msg_silent; 2212 int save_emsg_silent = emsg_silent; 2213 int save_emsg_noredir = emsg_noredir; 2214 int save_redir_execute = redir_execute; 2215 int save_redir_off = redir_off; 2216 garray_T save_ga; 2217 int save_msg_col = msg_col; 2218 int echo_output = FALSE; 2219 2220 rettv->vval.v_string = NULL; 2221 rettv->v_type = VAR_STRING; 2222 2223 if (argvars[arg_off].v_type == VAR_LIST) 2224 { 2225 list = argvars[arg_off].vval.v_list; 2226 if (list == NULL || list->lv_len == 0) 2227 // empty list, no commands, empty output 2228 return; 2229 ++list->lv_refcount; 2230 } 2231 else if (argvars[arg_off].v_type == VAR_JOB 2232 || argvars[arg_off].v_type == VAR_CHANNEL) 2233 { 2234 emsg(_(e_inval_string)); 2235 return; 2236 } 2237 else 2238 { 2239 cmd = tv_get_string_chk(&argvars[arg_off]); 2240 if (cmd == NULL) 2241 return; 2242 } 2243 2244 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN) 2245 { 2246 char_u buf[NUMBUFLEN]; 2247 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf); 2248 2249 if (s == NULL) 2250 return; 2251 if (*s == NUL) 2252 echo_output = TRUE; 2253 if (STRNCMP(s, "silent", 6) == 0) 2254 ++msg_silent; 2255 if (STRCMP(s, "silent!") == 0) 2256 { 2257 emsg_silent = TRUE; 2258 emsg_noredir = TRUE; 2259 } 2260 } 2261 else 2262 ++msg_silent; 2263 2264 if (redir_execute) 2265 save_ga = redir_execute_ga; 2266 ga_init2(&redir_execute_ga, (int)sizeof(char), 500); 2267 redir_execute = TRUE; 2268 redir_off = FALSE; 2269 if (!echo_output) 2270 msg_col = 0; // prevent leading spaces 2271 2272 if (cmd != NULL) 2273 do_cmdline_cmd(cmd); 2274 else 2275 { 2276 listitem_T *item; 2277 2278 CHECK_LIST_MATERIALIZE(list); 2279 item = list->lv_first; 2280 do_cmdline(NULL, get_list_line, (void *)&item, 2281 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED); 2282 --list->lv_refcount; 2283 } 2284 2285 // Need to append a NUL to the result. 2286 if (ga_grow(&redir_execute_ga, 1) == OK) 2287 { 2288 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL; 2289 rettv->vval.v_string = redir_execute_ga.ga_data; 2290 } 2291 else 2292 { 2293 ga_clear(&redir_execute_ga); 2294 rettv->vval.v_string = NULL; 2295 } 2296 msg_silent = save_msg_silent; 2297 emsg_silent = save_emsg_silent; 2298 emsg_noredir = save_emsg_noredir; 2299 2300 redir_execute = save_redir_execute; 2301 if (redir_execute) 2302 redir_execute_ga = save_ga; 2303 redir_off = save_redir_off; 2304 2305 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line. 2306 if (echo_output) 2307 // When not working silently: put it in column zero. A following 2308 // "echon" will overwrite the message, unavoidably. 2309 msg_col = 0; 2310 else 2311 // When working silently: Put it back where it was, since nothing 2312 // should have been written. 2313 msg_col = save_msg_col; 2314 } 2315 2316 /* 2317 * "execute()" function 2318 */ 2319 static void 2320 f_execute(typval_T *argvars, typval_T *rettv) 2321 { 2322 execute_common(argvars, rettv, 0); 2323 } 2324 2325 /* 2326 * "exists()" function 2327 */ 2328 static void 2329 f_exists(typval_T *argvars, typval_T *rettv) 2330 { 2331 char_u *p; 2332 int n = FALSE; 2333 2334 p = tv_get_string(&argvars[0]); 2335 if (*p == '$') // environment variable 2336 { 2337 // first try "normal" environment variables (fast) 2338 if (mch_getenv(p + 1) != NULL) 2339 n = TRUE; 2340 else 2341 { 2342 // try expanding things like $VIM and ${HOME} 2343 p = expand_env_save(p); 2344 if (p != NULL && *p != '$') 2345 n = TRUE; 2346 vim_free(p); 2347 } 2348 } 2349 else if (*p == '&' || *p == '+') // option 2350 { 2351 n = (get_option_tv(&p, NULL, TRUE) == OK); 2352 if (*skipwhite(p) != NUL) 2353 n = FALSE; // trailing garbage 2354 } 2355 else if (*p == '*') // internal or user defined function 2356 { 2357 n = function_exists(p + 1, FALSE); 2358 } 2359 else if (*p == '?') // internal function only 2360 { 2361 n = has_internal_func_name(p + 1); 2362 } 2363 else if (*p == ':') 2364 { 2365 n = cmd_exists(p + 1); 2366 } 2367 else if (*p == '#') 2368 { 2369 if (p[1] == '#') 2370 n = autocmd_supported(p + 2); 2371 else 2372 n = au_exists(p + 1); 2373 } 2374 else // internal variable 2375 { 2376 n = var_exists(p); 2377 } 2378 2379 rettv->vval.v_number = n; 2380 } 2381 2382 #ifdef FEAT_FLOAT 2383 /* 2384 * "exp()" function 2385 */ 2386 static void 2387 f_exp(typval_T *argvars, typval_T *rettv) 2388 { 2389 float_T f = 0.0; 2390 2391 rettv->v_type = VAR_FLOAT; 2392 if (get_float_arg(argvars, &f) == OK) 2393 rettv->vval.v_float = exp(f); 2394 else 2395 rettv->vval.v_float = 0.0; 2396 } 2397 #endif 2398 2399 /* 2400 * "expand()" function 2401 */ 2402 static void 2403 f_expand(typval_T *argvars, typval_T *rettv) 2404 { 2405 char_u *s; 2406 int len; 2407 char *errormsg; 2408 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND; 2409 expand_T xpc; 2410 int error = FALSE; 2411 char_u *result; 2412 2413 rettv->v_type = VAR_STRING; 2414 if (argvars[1].v_type != VAR_UNKNOWN 2415 && argvars[2].v_type != VAR_UNKNOWN 2416 && tv_get_number_chk(&argvars[2], &error) 2417 && !error) 2418 rettv_list_set(rettv, NULL); 2419 2420 s = tv_get_string(&argvars[0]); 2421 if (*s == '%' || *s == '#' || *s == '<') 2422 { 2423 ++emsg_off; 2424 result = eval_vars(s, s, &len, NULL, &errormsg, NULL); 2425 --emsg_off; 2426 if (rettv->v_type == VAR_LIST) 2427 { 2428 if (rettv_list_alloc(rettv) != FAIL && result != NULL) 2429 list_append_string(rettv->vval.v_list, result, -1); 2430 vim_free(result); 2431 } 2432 else 2433 rettv->vval.v_string = result; 2434 } 2435 else 2436 { 2437 // When the optional second argument is non-zero, don't remove matches 2438 // for 'wildignore' and don't put matches for 'suffixes' at the end. 2439 if (argvars[1].v_type != VAR_UNKNOWN 2440 && tv_get_number_chk(&argvars[1], &error)) 2441 options |= WILD_KEEP_ALL; 2442 if (!error) 2443 { 2444 ExpandInit(&xpc); 2445 xpc.xp_context = EXPAND_FILES; 2446 if (p_wic) 2447 options += WILD_ICASE; 2448 if (rettv->v_type == VAR_STRING) 2449 rettv->vval.v_string = ExpandOne(&xpc, s, NULL, 2450 options, WILD_ALL); 2451 else if (rettv_list_alloc(rettv) != FAIL) 2452 { 2453 int i; 2454 2455 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP); 2456 for (i = 0; i < xpc.xp_numfiles; i++) 2457 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); 2458 ExpandCleanup(&xpc); 2459 } 2460 } 2461 else 2462 rettv->vval.v_string = NULL; 2463 } 2464 } 2465 2466 /* 2467 * "expandcmd()" function 2468 * Expand all the special characters in a command string. 2469 */ 2470 static void 2471 f_expandcmd(typval_T *argvars, typval_T *rettv) 2472 { 2473 exarg_T eap; 2474 char_u *cmdstr; 2475 char *errormsg = NULL; 2476 2477 rettv->v_type = VAR_STRING; 2478 cmdstr = vim_strsave(tv_get_string(&argvars[0])); 2479 2480 memset(&eap, 0, sizeof(eap)); 2481 eap.cmd = cmdstr; 2482 eap.arg = cmdstr; 2483 eap.argt |= EX_NOSPC; 2484 eap.usefilter = FALSE; 2485 eap.nextcmd = NULL; 2486 eap.cmdidx = CMD_USER; 2487 2488 expand_filename(&eap, &cmdstr, &errormsg); 2489 if (errormsg != NULL && *errormsg != NUL) 2490 emsg(errormsg); 2491 2492 rettv->vval.v_string = cmdstr; 2493 } 2494 2495 /* 2496 * "feedkeys()" function 2497 */ 2498 static void 2499 f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED) 2500 { 2501 int remap = TRUE; 2502 int insert = FALSE; 2503 char_u *keys, *flags; 2504 char_u nbuf[NUMBUFLEN]; 2505 int typed = FALSE; 2506 int execute = FALSE; 2507 int dangerous = FALSE; 2508 int lowlevel = FALSE; 2509 char_u *keys_esc; 2510 2511 // This is not allowed in the sandbox. If the commands would still be 2512 // executed in the sandbox it would be OK, but it probably happens later, 2513 // when "sandbox" is no longer set. 2514 if (check_secure()) 2515 return; 2516 2517 keys = tv_get_string(&argvars[0]); 2518 2519 if (argvars[1].v_type != VAR_UNKNOWN) 2520 { 2521 flags = tv_get_string_buf(&argvars[1], nbuf); 2522 for ( ; *flags != NUL; ++flags) 2523 { 2524 switch (*flags) 2525 { 2526 case 'n': remap = FALSE; break; 2527 case 'm': remap = TRUE; break; 2528 case 't': typed = TRUE; break; 2529 case 'i': insert = TRUE; break; 2530 case 'x': execute = TRUE; break; 2531 case '!': dangerous = TRUE; break; 2532 case 'L': lowlevel = TRUE; break; 2533 } 2534 } 2535 } 2536 2537 if (*keys != NUL || execute) 2538 { 2539 // Need to escape K_SPECIAL and CSI before putting the string in the 2540 // typeahead buffer. 2541 keys_esc = vim_strsave_escape_csi(keys); 2542 if (keys_esc != NULL) 2543 { 2544 if (lowlevel) 2545 { 2546 #ifdef USE_INPUT_BUF 2547 int idx; 2548 int len = (int)STRLEN(keys); 2549 2550 for (idx = 0; idx < len; ++idx) 2551 { 2552 // if a CTRL-C was typed, set got_int, similar to what 2553 // happens in fill_input_buf() 2554 if (keys[idx] == 3 && ctrl_c_interrupts && typed) 2555 got_int = TRUE; 2556 add_to_input_buf(keys + idx, 1); 2557 } 2558 #else 2559 emsg(_("E980: lowlevel input not supported")); 2560 #endif 2561 } 2562 else 2563 { 2564 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), 2565 insert ? 0 : typebuf.tb_len, !typed, FALSE); 2566 if (vgetc_busy 2567 #ifdef FEAT_TIMERS 2568 || timer_busy 2569 #endif 2570 || input_busy) 2571 typebuf_was_filled = TRUE; 2572 } 2573 vim_free(keys_esc); 2574 2575 if (execute) 2576 { 2577 int save_msg_scroll = msg_scroll; 2578 2579 // Avoid a 1 second delay when the keys start Insert mode. 2580 msg_scroll = FALSE; 2581 2582 if (!dangerous) 2583 ++ex_normal_busy; 2584 exec_normal(TRUE, lowlevel, TRUE); 2585 if (!dangerous) 2586 --ex_normal_busy; 2587 2588 msg_scroll |= save_msg_scroll; 2589 } 2590 } 2591 } 2592 } 2593 2594 #ifdef FEAT_FLOAT 2595 /* 2596 * "float2nr({float})" function 2597 */ 2598 static void 2599 f_float2nr(typval_T *argvars, typval_T *rettv) 2600 { 2601 float_T f = 0.0; 2602 2603 if (get_float_arg(argvars, &f) == OK) 2604 { 2605 if (f <= -VARNUM_MAX + DBL_EPSILON) 2606 rettv->vval.v_number = -VARNUM_MAX; 2607 else if (f >= VARNUM_MAX - DBL_EPSILON) 2608 rettv->vval.v_number = VARNUM_MAX; 2609 else 2610 rettv->vval.v_number = (varnumber_T)f; 2611 } 2612 } 2613 2614 /* 2615 * "floor({float})" function 2616 */ 2617 static void 2618 f_floor(typval_T *argvars, typval_T *rettv) 2619 { 2620 float_T f = 0.0; 2621 2622 rettv->v_type = VAR_FLOAT; 2623 if (get_float_arg(argvars, &f) == OK) 2624 rettv->vval.v_float = floor(f); 2625 else 2626 rettv->vval.v_float = 0.0; 2627 } 2628 2629 /* 2630 * "fmod()" function 2631 */ 2632 static void 2633 f_fmod(typval_T *argvars, typval_T *rettv) 2634 { 2635 float_T fx = 0.0, fy = 0.0; 2636 2637 rettv->v_type = VAR_FLOAT; 2638 if (get_float_arg(argvars, &fx) == OK 2639 && get_float_arg(&argvars[1], &fy) == OK) 2640 rettv->vval.v_float = fmod(fx, fy); 2641 else 2642 rettv->vval.v_float = 0.0; 2643 } 2644 #endif 2645 2646 /* 2647 * "fnameescape({string})" function 2648 */ 2649 static void 2650 f_fnameescape(typval_T *argvars, typval_T *rettv) 2651 { 2652 rettv->vval.v_string = vim_strsave_fnameescape( 2653 tv_get_string(&argvars[0]), FALSE); 2654 rettv->v_type = VAR_STRING; 2655 } 2656 2657 /* 2658 * "foreground()" function 2659 */ 2660 static void 2661 f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 2662 { 2663 #ifdef FEAT_GUI 2664 if (gui.in_use) 2665 { 2666 gui_mch_set_foreground(); 2667 return; 2668 } 2669 #endif 2670 #if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL)) 2671 win32_set_foreground(); 2672 #endif 2673 } 2674 2675 static void 2676 common_function(typval_T *argvars, typval_T *rettv, int is_funcref) 2677 { 2678 char_u *s; 2679 char_u *name; 2680 int use_string = FALSE; 2681 partial_T *arg_pt = NULL; 2682 char_u *trans_name = NULL; 2683 int is_global = FALSE; 2684 2685 if (argvars[0].v_type == VAR_FUNC) 2686 { 2687 // function(MyFunc, [arg], dict) 2688 s = argvars[0].vval.v_string; 2689 } 2690 else if (argvars[0].v_type == VAR_PARTIAL 2691 && argvars[0].vval.v_partial != NULL) 2692 { 2693 // function(dict.MyFunc, [arg]) 2694 arg_pt = argvars[0].vval.v_partial; 2695 s = partial_name(arg_pt); 2696 } 2697 else 2698 { 2699 // function('MyFunc', [arg], dict) 2700 s = tv_get_string(&argvars[0]); 2701 use_string = TRUE; 2702 } 2703 2704 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref) 2705 { 2706 name = s; 2707 trans_name = trans_function_name(&name, &is_global, FALSE, 2708 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL); 2709 if (*name != NUL) 2710 s = NULL; 2711 } 2712 2713 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)) 2714 || (is_funcref && trans_name == NULL)) 2715 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s); 2716 // Don't check an autoload name for existence here. 2717 else if (trans_name != NULL && (is_funcref 2718 ? find_func(trans_name, is_global, NULL) == NULL 2719 : !translated_function_exists(trans_name, is_global))) 2720 semsg(_("E700: Unknown function: %s"), s); 2721 else 2722 { 2723 int dict_idx = 0; 2724 int arg_idx = 0; 2725 list_T *list = NULL; 2726 2727 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0) 2728 { 2729 char sid_buf[25]; 2730 int off = *s == 's' ? 2 : 5; 2731 2732 // Expand s: and <SID> into <SNR>nr_, so that the function can 2733 // also be called from another script. Using trans_function_name() 2734 // would also work, but some plugins depend on the name being 2735 // printable text. 2736 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid); 2737 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1); 2738 if (name != NULL) 2739 { 2740 STRCPY(name, sid_buf); 2741 STRCAT(name, s + off); 2742 } 2743 } 2744 else 2745 name = vim_strsave(s); 2746 2747 if (argvars[1].v_type != VAR_UNKNOWN) 2748 { 2749 if (argvars[2].v_type != VAR_UNKNOWN) 2750 { 2751 // function(name, [args], dict) 2752 arg_idx = 1; 2753 dict_idx = 2; 2754 } 2755 else if (argvars[1].v_type == VAR_DICT) 2756 // function(name, dict) 2757 dict_idx = 1; 2758 else 2759 // function(name, [args]) 2760 arg_idx = 1; 2761 if (dict_idx > 0) 2762 { 2763 if (argvars[dict_idx].v_type != VAR_DICT) 2764 { 2765 emsg(_("E922: expected a dict")); 2766 vim_free(name); 2767 goto theend; 2768 } 2769 if (argvars[dict_idx].vval.v_dict == NULL) 2770 dict_idx = 0; 2771 } 2772 if (arg_idx > 0) 2773 { 2774 if (argvars[arg_idx].v_type != VAR_LIST) 2775 { 2776 emsg(_("E923: Second argument of function() must be a list or a dict")); 2777 vim_free(name); 2778 goto theend; 2779 } 2780 list = argvars[arg_idx].vval.v_list; 2781 if (list == NULL || list->lv_len == 0) 2782 arg_idx = 0; 2783 else if (list->lv_len > MAX_FUNC_ARGS) 2784 { 2785 emsg_funcname((char *)e_toomanyarg, s); 2786 vim_free(name); 2787 goto theend; 2788 } 2789 } 2790 } 2791 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref) 2792 { 2793 partial_T *pt = ALLOC_CLEAR_ONE(partial_T); 2794 2795 // result is a VAR_PARTIAL 2796 if (pt == NULL) 2797 vim_free(name); 2798 else 2799 { 2800 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0)) 2801 { 2802 listitem_T *li; 2803 int i = 0; 2804 int arg_len = 0; 2805 int lv_len = 0; 2806 2807 if (arg_pt != NULL) 2808 arg_len = arg_pt->pt_argc; 2809 if (list != NULL) 2810 lv_len = list->lv_len; 2811 pt->pt_argc = arg_len + lv_len; 2812 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc); 2813 if (pt->pt_argv == NULL) 2814 { 2815 vim_free(pt); 2816 vim_free(name); 2817 goto theend; 2818 } 2819 for (i = 0; i < arg_len; i++) 2820 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]); 2821 if (lv_len > 0) 2822 { 2823 CHECK_LIST_MATERIALIZE(list); 2824 FOR_ALL_LIST_ITEMS(list, li) 2825 copy_tv(&li->li_tv, &pt->pt_argv[i++]); 2826 } 2827 } 2828 2829 // For "function(dict.func, [], dict)" and "func" is a partial 2830 // use "dict". That is backwards compatible. 2831 if (dict_idx > 0) 2832 { 2833 // The dict is bound explicitly, pt_auto is FALSE. 2834 pt->pt_dict = argvars[dict_idx].vval.v_dict; 2835 ++pt->pt_dict->dv_refcount; 2836 } 2837 else if (arg_pt != NULL) 2838 { 2839 // If the dict was bound automatically the result is also 2840 // bound automatically. 2841 pt->pt_dict = arg_pt->pt_dict; 2842 pt->pt_auto = arg_pt->pt_auto; 2843 if (pt->pt_dict != NULL) 2844 ++pt->pt_dict->dv_refcount; 2845 } 2846 2847 pt->pt_refcount = 1; 2848 if (arg_pt != NULL && arg_pt->pt_func != NULL) 2849 { 2850 pt->pt_func = arg_pt->pt_func; 2851 func_ptr_ref(pt->pt_func); 2852 vim_free(name); 2853 } 2854 else if (is_funcref) 2855 { 2856 pt->pt_func = find_func(trans_name, is_global, NULL); 2857 func_ptr_ref(pt->pt_func); 2858 vim_free(name); 2859 } 2860 else 2861 { 2862 pt->pt_name = name; 2863 func_ref(name); 2864 } 2865 } 2866 rettv->v_type = VAR_PARTIAL; 2867 rettv->vval.v_partial = pt; 2868 } 2869 else 2870 { 2871 // result is a VAR_FUNC 2872 rettv->v_type = VAR_FUNC; 2873 rettv->vval.v_string = name; 2874 func_ref(name); 2875 } 2876 } 2877 theend: 2878 vim_free(trans_name); 2879 } 2880 2881 /* 2882 * "funcref()" function 2883 */ 2884 static void 2885 f_funcref(typval_T *argvars, typval_T *rettv) 2886 { 2887 common_function(argvars, rettv, TRUE); 2888 } 2889 2890 static type_T * 2891 ret_f_function(int argcount, type_T **argtypes) 2892 { 2893 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING) 2894 return &t_func_any; 2895 return &t_func_void; 2896 } 2897 2898 /* 2899 * "function()" function 2900 */ 2901 static void 2902 f_function(typval_T *argvars, typval_T *rettv) 2903 { 2904 common_function(argvars, rettv, FALSE); 2905 } 2906 2907 /* 2908 * "garbagecollect()" function 2909 */ 2910 static void 2911 f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED) 2912 { 2913 // This is postponed until we are back at the toplevel, because we may be 2914 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". 2915 want_garbage_collect = TRUE; 2916 2917 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1) 2918 garbage_collect_at_exit = TRUE; 2919 } 2920 2921 /* 2922 * "get()" function 2923 */ 2924 static void 2925 f_get(typval_T *argvars, typval_T *rettv) 2926 { 2927 listitem_T *li; 2928 list_T *l; 2929 dictitem_T *di; 2930 dict_T *d; 2931 typval_T *tv = NULL; 2932 int what_is_dict = FALSE; 2933 2934 if (argvars[0].v_type == VAR_BLOB) 2935 { 2936 int error = FALSE; 2937 int idx = tv_get_number_chk(&argvars[1], &error); 2938 2939 if (!error) 2940 { 2941 rettv->v_type = VAR_NUMBER; 2942 if (idx < 0) 2943 idx = blob_len(argvars[0].vval.v_blob) + idx; 2944 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob)) 2945 rettv->vval.v_number = -1; 2946 else 2947 { 2948 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx); 2949 tv = rettv; 2950 } 2951 } 2952 } 2953 else if (argvars[0].v_type == VAR_LIST) 2954 { 2955 if ((l = argvars[0].vval.v_list) != NULL) 2956 { 2957 int error = FALSE; 2958 2959 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error)); 2960 if (!error && li != NULL) 2961 tv = &li->li_tv; 2962 } 2963 } 2964 else if (argvars[0].v_type == VAR_DICT) 2965 { 2966 if ((d = argvars[0].vval.v_dict) != NULL) 2967 { 2968 di = dict_find(d, tv_get_string(&argvars[1]), -1); 2969 if (di != NULL) 2970 tv = &di->di_tv; 2971 } 2972 } 2973 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC) 2974 { 2975 partial_T *pt; 2976 partial_T fref_pt; 2977 2978 if (argvars[0].v_type == VAR_PARTIAL) 2979 pt = argvars[0].vval.v_partial; 2980 else 2981 { 2982 CLEAR_FIELD(fref_pt); 2983 fref_pt.pt_name = argvars[0].vval.v_string; 2984 pt = &fref_pt; 2985 } 2986 2987 if (pt != NULL) 2988 { 2989 char_u *what = tv_get_string(&argvars[1]); 2990 char_u *n; 2991 2992 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0) 2993 { 2994 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING); 2995 n = partial_name(pt); 2996 if (n == NULL) 2997 rettv->vval.v_string = NULL; 2998 else 2999 { 3000 rettv->vval.v_string = vim_strsave(n); 3001 if (rettv->v_type == VAR_FUNC) 3002 func_ref(rettv->vval.v_string); 3003 } 3004 } 3005 else if (STRCMP(what, "dict") == 0) 3006 { 3007 what_is_dict = TRUE; 3008 if (pt->pt_dict != NULL) 3009 rettv_dict_set(rettv, pt->pt_dict); 3010 } 3011 else if (STRCMP(what, "args") == 0) 3012 { 3013 rettv->v_type = VAR_LIST; 3014 if (rettv_list_alloc(rettv) == OK) 3015 { 3016 int i; 3017 3018 for (i = 0; i < pt->pt_argc; ++i) 3019 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]); 3020 } 3021 } 3022 else 3023 semsg(_(e_invarg2), what); 3024 3025 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the 3026 // third argument 3027 if (!what_is_dict) 3028 return; 3029 } 3030 } 3031 else 3032 semsg(_(e_listdictblobarg), "get()"); 3033 3034 if (tv == NULL) 3035 { 3036 if (argvars[2].v_type != VAR_UNKNOWN) 3037 copy_tv(&argvars[2], rettv); 3038 } 3039 else 3040 copy_tv(tv, rettv); 3041 } 3042 3043 /* 3044 * "getchangelist()" function 3045 */ 3046 static void 3047 f_getchangelist(typval_T *argvars, typval_T *rettv) 3048 { 3049 #ifdef FEAT_JUMPLIST 3050 buf_T *buf; 3051 int i; 3052 list_T *l; 3053 dict_T *d; 3054 #endif 3055 3056 if (rettv_list_alloc(rettv) != OK) 3057 return; 3058 3059 #ifdef FEAT_JUMPLIST 3060 if (argvars[0].v_type == VAR_UNKNOWN) 3061 buf = curbuf; 3062 else 3063 { 3064 (void)tv_get_number(&argvars[0]); // issue errmsg if type error 3065 ++emsg_off; 3066 buf = tv_get_buf(&argvars[0], FALSE); 3067 --emsg_off; 3068 } 3069 if (buf == NULL) 3070 return; 3071 3072 l = list_alloc(); 3073 if (l == NULL) 3074 return; 3075 3076 if (list_append_list(rettv->vval.v_list, l) == FAIL) 3077 return; 3078 /* 3079 * The current window change list index tracks only the position in the 3080 * current buffer change list. For other buffers, use the change list 3081 * length as the current index. 3082 */ 3083 list_append_number(rettv->vval.v_list, 3084 (varnumber_T)((buf == curwin->w_buffer) 3085 ? curwin->w_changelistidx : buf->b_changelistlen)); 3086 3087 for (i = 0; i < buf->b_changelistlen; ++i) 3088 { 3089 if (buf->b_changelist[i].lnum == 0) 3090 continue; 3091 if ((d = dict_alloc()) == NULL) 3092 return; 3093 if (list_append_dict(l, d) == FAIL) 3094 return; 3095 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum); 3096 dict_add_number(d, "col", (long)buf->b_changelist[i].col); 3097 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd); 3098 } 3099 #endif 3100 } 3101 3102 /* 3103 * "getcharsearch()" function 3104 */ 3105 static void 3106 f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv) 3107 { 3108 if (rettv_dict_alloc(rettv) != FAIL) 3109 { 3110 dict_T *dict = rettv->vval.v_dict; 3111 3112 dict_add_string(dict, "char", last_csearch()); 3113 dict_add_number(dict, "forward", last_csearch_forward()); 3114 dict_add_number(dict, "until", last_csearch_until()); 3115 } 3116 } 3117 3118 /* 3119 * "getenv()" function 3120 */ 3121 static void 3122 f_getenv(typval_T *argvars, typval_T *rettv) 3123 { 3124 int mustfree = FALSE; 3125 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree); 3126 3127 if (p == NULL) 3128 { 3129 rettv->v_type = VAR_SPECIAL; 3130 rettv->vval.v_number = VVAL_NULL; 3131 return; 3132 } 3133 if (!mustfree) 3134 p = vim_strsave(p); 3135 rettv->vval.v_string = p; 3136 rettv->v_type = VAR_STRING; 3137 } 3138 3139 /* 3140 * "getfontname()" function 3141 */ 3142 static void 3143 f_getfontname(typval_T *argvars UNUSED, typval_T *rettv) 3144 { 3145 rettv->v_type = VAR_STRING; 3146 rettv->vval.v_string = NULL; 3147 #ifdef FEAT_GUI 3148 if (gui.in_use) 3149 { 3150 GuiFont font; 3151 char_u *name = NULL; 3152 3153 if (argvars[0].v_type == VAR_UNKNOWN) 3154 { 3155 // Get the "Normal" font. Either the name saved by 3156 // hl_set_font_name() or from the font ID. 3157 font = gui.norm_font; 3158 name = hl_get_font_name(); 3159 } 3160 else 3161 { 3162 name = tv_get_string(&argvars[0]); 3163 if (STRCMP(name, "*") == 0) // don't use font dialog 3164 return; 3165 font = gui_mch_get_font(name, FALSE); 3166 if (font == NOFONT) 3167 return; // Invalid font name, return empty string. 3168 } 3169 rettv->vval.v_string = gui_mch_get_fontname(font, name); 3170 if (argvars[0].v_type != VAR_UNKNOWN) 3171 gui_mch_free_font(font); 3172 } 3173 #endif 3174 } 3175 3176 /* 3177 * "getjumplist()" function 3178 */ 3179 static void 3180 f_getjumplist(typval_T *argvars, typval_T *rettv) 3181 { 3182 #ifdef FEAT_JUMPLIST 3183 win_T *wp; 3184 int i; 3185 list_T *l; 3186 dict_T *d; 3187 #endif 3188 3189 if (rettv_list_alloc(rettv) != OK) 3190 return; 3191 3192 #ifdef FEAT_JUMPLIST 3193 wp = find_tabwin(&argvars[0], &argvars[1], NULL); 3194 if (wp == NULL) 3195 return; 3196 3197 cleanup_jumplist(wp, TRUE); 3198 3199 l = list_alloc(); 3200 if (l == NULL) 3201 return; 3202 3203 if (list_append_list(rettv->vval.v_list, l) == FAIL) 3204 return; 3205 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx); 3206 3207 for (i = 0; i < wp->w_jumplistlen; ++i) 3208 { 3209 if (wp->w_jumplist[i].fmark.mark.lnum == 0) 3210 continue; 3211 if ((d = dict_alloc()) == NULL) 3212 return; 3213 if (list_append_dict(l, d) == FAIL) 3214 return; 3215 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum); 3216 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col); 3217 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd); 3218 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum); 3219 if (wp->w_jumplist[i].fname != NULL) 3220 dict_add_string(d, "filename", wp->w_jumplist[i].fname); 3221 } 3222 #endif 3223 } 3224 3225 /* 3226 * "getpid()" function 3227 */ 3228 static void 3229 f_getpid(typval_T *argvars UNUSED, typval_T *rettv) 3230 { 3231 rettv->vval.v_number = mch_get_pid(); 3232 } 3233 3234 static void 3235 getpos_both( 3236 typval_T *argvars, 3237 typval_T *rettv, 3238 int getcurpos) 3239 { 3240 pos_T *fp; 3241 list_T *l; 3242 int fnum = -1; 3243 3244 if (rettv_list_alloc(rettv) == OK) 3245 { 3246 l = rettv->vval.v_list; 3247 if (getcurpos) 3248 fp = &curwin->w_cursor; 3249 else 3250 fp = var2fpos(&argvars[0], TRUE, &fnum); 3251 if (fnum != -1) 3252 list_append_number(l, (varnumber_T)fnum); 3253 else 3254 list_append_number(l, (varnumber_T)0); 3255 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum 3256 : (varnumber_T)0); 3257 list_append_number(l, (fp != NULL) 3258 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1) 3259 : (varnumber_T)0); 3260 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd : 3261 (varnumber_T)0); 3262 if (getcurpos) 3263 { 3264 int save_set_curswant = curwin->w_set_curswant; 3265 colnr_T save_curswant = curwin->w_curswant; 3266 colnr_T save_virtcol = curwin->w_virtcol; 3267 3268 update_curswant(); 3269 list_append_number(l, curwin->w_curswant == MAXCOL ? 3270 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1); 3271 3272 // Do not change "curswant", as it is unexpected that a get 3273 // function has a side effect. 3274 if (save_set_curswant) 3275 { 3276 curwin->w_set_curswant = save_set_curswant; 3277 curwin->w_curswant = save_curswant; 3278 curwin->w_virtcol = save_virtcol; 3279 curwin->w_valid &= ~VALID_VIRTCOL; 3280 } 3281 } 3282 } 3283 else 3284 rettv->vval.v_number = FALSE; 3285 } 3286 3287 /* 3288 * "getcurpos()" function 3289 */ 3290 static void 3291 f_getcurpos(typval_T *argvars, typval_T *rettv) 3292 { 3293 getpos_both(argvars, rettv, TRUE); 3294 } 3295 3296 /* 3297 * "getpos(string)" function 3298 */ 3299 static void 3300 f_getpos(typval_T *argvars, typval_T *rettv) 3301 { 3302 getpos_both(argvars, rettv, FALSE); 3303 } 3304 3305 /* 3306 * "getreg()" function 3307 */ 3308 static void 3309 f_getreg(typval_T *argvars, typval_T *rettv) 3310 { 3311 char_u *strregname; 3312 int regname; 3313 int arg2 = FALSE; 3314 int return_list = FALSE; 3315 int error = FALSE; 3316 3317 if (argvars[0].v_type != VAR_UNKNOWN) 3318 { 3319 strregname = tv_get_string_chk(&argvars[0]); 3320 error = strregname == NULL; 3321 if (argvars[1].v_type != VAR_UNKNOWN) 3322 { 3323 arg2 = (int)tv_get_number_chk(&argvars[1], &error); 3324 if (!error && argvars[2].v_type != VAR_UNKNOWN) 3325 return_list = (int)tv_get_number_chk(&argvars[2], &error); 3326 } 3327 } 3328 else 3329 strregname = get_vim_var_str(VV_REG); 3330 3331 if (error) 3332 return; 3333 3334 regname = (strregname == NULL ? '"' : *strregname); 3335 if (regname == 0) 3336 regname = '"'; 3337 3338 if (return_list) 3339 { 3340 rettv->v_type = VAR_LIST; 3341 rettv->vval.v_list = (list_T *)get_reg_contents(regname, 3342 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST); 3343 if (rettv->vval.v_list == NULL) 3344 (void)rettv_list_alloc(rettv); 3345 else 3346 ++rettv->vval.v_list->lv_refcount; 3347 } 3348 else 3349 { 3350 rettv->v_type = VAR_STRING; 3351 rettv->vval.v_string = get_reg_contents(regname, 3352 arg2 ? GREG_EXPR_SRC : 0); 3353 } 3354 } 3355 3356 /* 3357 * "getregtype()" function 3358 */ 3359 static void 3360 f_getregtype(typval_T *argvars, typval_T *rettv) 3361 { 3362 char_u *strregname; 3363 int regname; 3364 char_u buf[NUMBUFLEN + 2]; 3365 long reglen = 0; 3366 3367 if (argvars[0].v_type != VAR_UNKNOWN) 3368 { 3369 strregname = tv_get_string_chk(&argvars[0]); 3370 if (strregname == NULL) // type error; errmsg already given 3371 { 3372 rettv->v_type = VAR_STRING; 3373 rettv->vval.v_string = NULL; 3374 return; 3375 } 3376 } 3377 else 3378 // Default to v:register 3379 strregname = get_vim_var_str(VV_REG); 3380 3381 regname = (strregname == NULL ? '"' : *strregname); 3382 if (regname == 0) 3383 regname = '"'; 3384 3385 buf[0] = NUL; 3386 buf[1] = NUL; 3387 switch (get_reg_type(regname, ®len)) 3388 { 3389 case MLINE: buf[0] = 'V'; break; 3390 case MCHAR: buf[0] = 'v'; break; 3391 case MBLOCK: 3392 buf[0] = Ctrl_V; 3393 sprintf((char *)buf + 1, "%ld", reglen + 1); 3394 break; 3395 } 3396 rettv->v_type = VAR_STRING; 3397 rettv->vval.v_string = vim_strsave(buf); 3398 } 3399 3400 /* 3401 * "gettagstack()" function 3402 */ 3403 static void 3404 f_gettagstack(typval_T *argvars, typval_T *rettv) 3405 { 3406 win_T *wp = curwin; // default is current window 3407 3408 if (rettv_dict_alloc(rettv) != OK) 3409 return; 3410 3411 if (argvars[0].v_type != VAR_UNKNOWN) 3412 { 3413 wp = find_win_by_nr_or_id(&argvars[0]); 3414 if (wp == NULL) 3415 return; 3416 } 3417 3418 get_tagstack(wp, rettv->vval.v_dict); 3419 } 3420 3421 // for VIM_VERSION_ defines 3422 #include "version.h" 3423 3424 /* 3425 * "has()" function 3426 */ 3427 void 3428 f_has(typval_T *argvars, typval_T *rettv) 3429 { 3430 int i; 3431 char_u *name; 3432 int x = FALSE; 3433 int n = FALSE; 3434 typedef struct { 3435 char *name; 3436 short present; 3437 } has_item_T; 3438 static has_item_T has_list[] = 3439 { 3440 {"amiga", 3441 #ifdef AMIGA 3442 1 3443 #else 3444 0 3445 #endif 3446 }, 3447 {"arp", 3448 #if defined(AMIGA) && defined(FEAT_ARP) 3449 1 3450 #else 3451 0 3452 #endif 3453 }, 3454 {"beos", 3455 #ifdef __BEOS__ 3456 1 3457 #else 3458 0 3459 #endif 3460 }, 3461 {"haiku", 3462 #ifdef __HAIKU__ 3463 1 3464 #else 3465 0 3466 #endif 3467 }, 3468 {"bsd", 3469 #if defined(BSD) && !defined(MACOS_X) 3470 1 3471 #else 3472 0 3473 #endif 3474 }, 3475 {"hpux", 3476 #ifdef hpux 3477 1 3478 #else 3479 0 3480 #endif 3481 }, 3482 {"linux", 3483 #ifdef __linux__ 3484 1 3485 #else 3486 0 3487 #endif 3488 }, 3489 {"mac", // Mac OS X (and, once, Mac OS Classic) 3490 #ifdef MACOS_X 3491 1 3492 #else 3493 0 3494 #endif 3495 }, 3496 {"osx", // Mac OS X 3497 #ifdef MACOS_X 3498 1 3499 #else 3500 0 3501 #endif 3502 }, 3503 {"macunix", // Mac OS X, with the darwin feature 3504 #if defined(MACOS_X) && defined(MACOS_X_DARWIN) 3505 1 3506 #else 3507 0 3508 #endif 3509 }, 3510 {"osxdarwin", // synonym for macunix 3511 #if defined(MACOS_X) && defined(MACOS_X_DARWIN) 3512 1 3513 #else 3514 0 3515 #endif 3516 }, 3517 {"qnx", 3518 #ifdef __QNX__ 3519 1 3520 #else 3521 0 3522 #endif 3523 }, 3524 {"sun", 3525 #ifdef SUN_SYSTEM 3526 1 3527 #else 3528 0 3529 #endif 3530 }, 3531 {"unix", 3532 #ifdef UNIX 3533 1 3534 #else 3535 0 3536 #endif 3537 }, 3538 {"vms", 3539 #ifdef VMS 3540 1 3541 #else 3542 0 3543 #endif 3544 }, 3545 {"win32", 3546 #ifdef MSWIN 3547 1 3548 #else 3549 0 3550 #endif 3551 }, 3552 {"win32unix", 3553 #if defined(UNIX) && defined(__CYGWIN__) 3554 1 3555 #else 3556 0 3557 #endif 3558 }, 3559 {"win64", 3560 #ifdef _WIN64 3561 1 3562 #else 3563 0 3564 #endif 3565 }, 3566 {"ebcdic", 3567 #ifdef EBCDIC 3568 1 3569 #else 3570 0 3571 #endif 3572 }, 3573 {"fname_case", 3574 #ifndef CASE_INSENSITIVE_FILENAME 3575 1 3576 #else 3577 0 3578 #endif 3579 }, 3580 {"acl", 3581 #ifdef HAVE_ACL 3582 1 3583 #else 3584 0 3585 #endif 3586 }, 3587 {"arabic", 3588 #ifdef FEAT_ARABIC 3589 1 3590 #else 3591 0 3592 #endif 3593 }, 3594 {"autocmd", 1}, 3595 {"autochdir", 3596 #ifdef FEAT_AUTOCHDIR 3597 1 3598 #else 3599 0 3600 #endif 3601 }, 3602 {"autoservername", 3603 #ifdef FEAT_AUTOSERVERNAME 3604 1 3605 #else 3606 0 3607 #endif 3608 }, 3609 {"balloon_eval", 3610 #ifdef FEAT_BEVAL_GUI 3611 1 3612 #else 3613 0 3614 #endif 3615 }, 3616 {"balloon_multiline", 3617 #if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN) 3618 // MS-Windows requires runtime check, see below 3619 1 3620 #else 3621 0 3622 #endif 3623 }, 3624 {"balloon_eval_term", 3625 #ifdef FEAT_BEVAL_TERM 3626 1 3627 #else 3628 0 3629 #endif 3630 }, 3631 {"builtin_terms", 3632 #if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS) 3633 1 3634 #else 3635 0 3636 #endif 3637 }, 3638 {"all_builtin_terms", 3639 #if defined(ALL_BUILTIN_TCAPS) 3640 1 3641 #else 3642 0 3643 #endif 3644 }, 3645 {"browsefilter", 3646 #if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \ 3647 || defined(FEAT_GUI_MSWIN) \ 3648 || defined(FEAT_GUI_MOTIF)) 3649 1 3650 #else 3651 0 3652 #endif 3653 }, 3654 {"byte_offset", 3655 #ifdef FEAT_BYTEOFF 3656 1 3657 #else 3658 0 3659 #endif 3660 }, 3661 {"channel", 3662 #ifdef FEAT_JOB_CHANNEL 3663 1 3664 #else 3665 0 3666 #endif 3667 }, 3668 {"cindent", 3669 #ifdef FEAT_CINDENT 3670 1 3671 #else 3672 0 3673 #endif 3674 }, 3675 {"clientserver", 3676 #ifdef FEAT_CLIENTSERVER 3677 1 3678 #else 3679 0 3680 #endif 3681 }, 3682 {"clipboard", 3683 #ifdef FEAT_CLIPBOARD 3684 1 3685 #else 3686 0 3687 #endif 3688 }, 3689 {"cmdline_compl", 1}, 3690 {"cmdline_hist", 1}, 3691 {"comments", 1}, 3692 {"conceal", 3693 #ifdef FEAT_CONCEAL 3694 1 3695 #else 3696 0 3697 #endif 3698 }, 3699 {"cryptv", 3700 #ifdef FEAT_CRYPT 3701 1 3702 #else 3703 0 3704 #endif 3705 }, 3706 {"crypt-blowfish", 3707 #ifdef FEAT_CRYPT 3708 1 3709 #else 3710 0 3711 #endif 3712 }, 3713 {"crypt-blowfish2", 3714 #ifdef FEAT_CRYPT 3715 1 3716 #else 3717 0 3718 #endif 3719 }, 3720 {"cscope", 3721 #ifdef FEAT_CSCOPE 3722 1 3723 #else 3724 0 3725 #endif 3726 }, 3727 {"cursorbind", 1}, 3728 {"cursorshape", 3729 #ifdef CURSOR_SHAPE 3730 1 3731 #else 3732 0 3733 #endif 3734 }, 3735 {"debug", 3736 #ifdef DEBUG 3737 1 3738 #else 3739 0 3740 #endif 3741 }, 3742 {"dialog_con", 3743 #ifdef FEAT_CON_DIALOG 3744 1 3745 #else 3746 0 3747 #endif 3748 }, 3749 {"dialog_gui", 3750 #ifdef FEAT_GUI_DIALOG 3751 1 3752 #else 3753 0 3754 #endif 3755 }, 3756 {"diff", 3757 #ifdef FEAT_DIFF 3758 1 3759 #else 3760 0 3761 #endif 3762 }, 3763 {"digraphs", 3764 #ifdef FEAT_DIGRAPHS 3765 1 3766 #else 3767 0 3768 #endif 3769 }, 3770 {"directx", 3771 #ifdef FEAT_DIRECTX 3772 1 3773 #else 3774 0 3775 #endif 3776 }, 3777 {"dnd", 3778 #ifdef FEAT_DND 3779 1 3780 #else 3781 0 3782 #endif 3783 }, 3784 {"emacs_tags", 3785 #ifdef FEAT_EMACS_TAGS 3786 1 3787 #else 3788 0 3789 #endif 3790 }, 3791 {"eval", 1}, // always present, of course! 3792 {"ex_extra", 1}, // graduated feature 3793 {"extra_search", 3794 #ifdef FEAT_SEARCH_EXTRA 3795 1 3796 #else 3797 0 3798 #endif 3799 }, 3800 {"file_in_path", 3801 #ifdef FEAT_SEARCHPATH 3802 1 3803 #else 3804 0 3805 #endif 3806 }, 3807 {"filterpipe", 3808 #if defined(FEAT_FILTERPIPE) && !defined(VIMDLL) 3809 1 3810 #else 3811 0 3812 #endif 3813 }, 3814 {"find_in_path", 3815 #ifdef FEAT_FIND_ID 3816 1 3817 #else 3818 0 3819 #endif 3820 }, 3821 {"float", 3822 #ifdef FEAT_FLOAT 3823 1 3824 #else 3825 0 3826 #endif 3827 }, 3828 {"folding", 3829 #ifdef FEAT_FOLDING 3830 1 3831 #else 3832 0 3833 #endif 3834 }, 3835 {"footer", 3836 #ifdef FEAT_FOOTER 3837 1 3838 #else 3839 0 3840 #endif 3841 }, 3842 {"fork", 3843 #if !defined(USE_SYSTEM) && defined(UNIX) 3844 1 3845 #else 3846 0 3847 #endif 3848 }, 3849 {"gettext", 3850 #ifdef FEAT_GETTEXT 3851 1 3852 #else 3853 0 3854 #endif 3855 }, 3856 {"gui", 3857 #ifdef FEAT_GUI 3858 1 3859 #else 3860 0 3861 #endif 3862 }, 3863 {"gui_neXtaw", 3864 #if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW) 3865 1 3866 #else 3867 0 3868 #endif 3869 }, 3870 {"gui_athena", 3871 #if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW) 3872 1 3873 #else 3874 0 3875 #endif 3876 }, 3877 {"gui_gtk", 3878 #ifdef FEAT_GUI_GTK 3879 1 3880 #else 3881 0 3882 #endif 3883 }, 3884 {"gui_gtk2", 3885 #if defined(FEAT_GUI_GTK) && !defined(USE_GTK3) 3886 1 3887 #else 3888 0 3889 #endif 3890 }, 3891 {"gui_gtk3", 3892 #if defined(FEAT_GUI_GTK) && defined(USE_GTK3) 3893 1 3894 #else 3895 0 3896 #endif 3897 }, 3898 {"gui_gnome", 3899 #ifdef FEAT_GUI_GNOME 3900 1 3901 #else 3902 0 3903 #endif 3904 }, 3905 {"gui_haiku", 3906 #ifdef FEAT_GUI_HAIKU 3907 1 3908 #else 3909 0 3910 #endif 3911 }, 3912 {"gui_mac", 3913 #ifdef FEAT_GUI_MAC 3914 1 3915 #else 3916 0 3917 #endif 3918 }, 3919 {"gui_motif", 3920 #ifdef FEAT_GUI_MOTIF 3921 1 3922 #else 3923 0 3924 #endif 3925 }, 3926 {"gui_photon", 3927 #ifdef FEAT_GUI_PHOTON 3928 1 3929 #else 3930 0 3931 #endif 3932 }, 3933 {"gui_win32", 3934 #ifdef FEAT_GUI_MSWIN 3935 1 3936 #else 3937 0 3938 #endif 3939 }, 3940 {"iconv", 3941 #if defined(HAVE_ICONV_H) && defined(USE_ICONV) 3942 1 3943 #else 3944 0 3945 #endif 3946 }, 3947 {"insert_expand", 1}, 3948 {"ipv6", 3949 #ifdef FEAT_IPV6 3950 1 3951 #else 3952 0 3953 #endif 3954 }, 3955 {"job", 3956 #ifdef FEAT_JOB_CHANNEL 3957 1 3958 #else 3959 0 3960 #endif 3961 }, 3962 {"jumplist", 3963 #ifdef FEAT_JUMPLIST 3964 1 3965 #else 3966 0 3967 #endif 3968 }, 3969 {"keymap", 3970 #ifdef FEAT_KEYMAP 3971 1 3972 #else 3973 0 3974 #endif 3975 }, 3976 {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure 3977 {"langmap", 3978 #ifdef FEAT_LANGMAP 3979 1 3980 #else 3981 0 3982 #endif 3983 }, 3984 {"libcall", 3985 #ifdef FEAT_LIBCALL 3986 1 3987 #else 3988 0 3989 #endif 3990 }, 3991 {"linebreak", 3992 #ifdef FEAT_LINEBREAK 3993 1 3994 #else 3995 0 3996 #endif 3997 }, 3998 {"lispindent", 3999 #ifdef FEAT_LISP 4000 1 4001 #else 4002 0 4003 #endif 4004 }, 4005 {"listcmds", 1}, 4006 {"localmap", 1}, 4007 {"lua", 4008 #if defined(FEAT_LUA) && !defined(DYNAMIC_LUA) 4009 1 4010 #else 4011 0 4012 #endif 4013 }, 4014 {"menu", 4015 #ifdef FEAT_MENU 4016 1 4017 #else 4018 0 4019 #endif 4020 }, 4021 {"mksession", 4022 #ifdef FEAT_SESSION 4023 1 4024 #else 4025 0 4026 #endif 4027 }, 4028 {"modify_fname", 1}, 4029 {"mouse", 1}, 4030 {"mouseshape", 4031 #ifdef FEAT_MOUSESHAPE 4032 1 4033 #else 4034 0 4035 #endif 4036 }, 4037 {"mouse_dec", 4038 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC) 4039 1 4040 #else 4041 0 4042 #endif 4043 }, 4044 {"mouse_gpm", 4045 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM) 4046 1 4047 #else 4048 0 4049 #endif 4050 }, 4051 {"mouse_jsbterm", 4052 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB) 4053 1 4054 #else 4055 0 4056 #endif 4057 }, 4058 {"mouse_netterm", 4059 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET) 4060 1 4061 #else 4062 0 4063 #endif 4064 }, 4065 {"mouse_pterm", 4066 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM) 4067 1 4068 #else 4069 0 4070 #endif 4071 }, 4072 {"mouse_sgr", 4073 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM) 4074 1 4075 #else 4076 0 4077 #endif 4078 }, 4079 {"mouse_sysmouse", 4080 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE) 4081 1 4082 #else 4083 0 4084 #endif 4085 }, 4086 {"mouse_urxvt", 4087 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT) 4088 1 4089 #else 4090 0 4091 #endif 4092 }, 4093 {"mouse_xterm", 4094 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM) 4095 1 4096 #else 4097 0 4098 #endif 4099 }, 4100 {"multi_byte", 1}, 4101 {"multi_byte_ime", 4102 #ifdef FEAT_MBYTE_IME 4103 1 4104 #else 4105 0 4106 #endif 4107 }, 4108 {"multi_lang", 4109 #ifdef FEAT_MULTI_LANG 4110 1 4111 #else 4112 0 4113 #endif 4114 }, 4115 {"mzscheme", 4116 #if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME) 4117 1 4118 #else 4119 0 4120 #endif 4121 }, 4122 {"num64", 1}, 4123 {"ole", 4124 #ifdef FEAT_OLE 4125 1 4126 #else 4127 0 4128 #endif 4129 }, 4130 {"packages", 4131 #ifdef FEAT_EVAL 4132 1 4133 #else 4134 0 4135 #endif 4136 }, 4137 {"path_extra", 4138 #ifdef FEAT_PATH_EXTRA 4139 1 4140 #else 4141 0 4142 #endif 4143 }, 4144 {"perl", 4145 #if defined(FEAT_PERL) && !defined(DYNAMIC_PERL) 4146 1 4147 #else 4148 0 4149 #endif 4150 }, 4151 {"persistent_undo", 4152 #ifdef FEAT_PERSISTENT_UNDO 4153 1 4154 #else 4155 0 4156 #endif 4157 }, 4158 {"python_compiled", 4159 #if defined(FEAT_PYTHON) 4160 1 4161 #else 4162 0 4163 #endif 4164 }, 4165 {"python_dynamic", 4166 #if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON) 4167 1 4168 #else 4169 0 4170 #endif 4171 }, 4172 {"python", 4173 #if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON) 4174 1 4175 #else 4176 0 4177 #endif 4178 }, 4179 {"pythonx", 4180 #if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \ 4181 || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)) 4182 1 4183 #else 4184 0 4185 #endif 4186 }, 4187 {"python3_compiled", 4188 #if defined(FEAT_PYTHON3) 4189 1 4190 #else 4191 0 4192 #endif 4193 }, 4194 {"python3_dynamic", 4195 #if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3) 4196 1 4197 #else 4198 0 4199 #endif 4200 }, 4201 {"python3", 4202 #if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3) 4203 1 4204 #else 4205 0 4206 #endif 4207 }, 4208 {"popupwin", 4209 #ifdef FEAT_PROP_POPUP 4210 1 4211 #else 4212 0 4213 #endif 4214 }, 4215 {"postscript", 4216 #ifdef FEAT_POSTSCRIPT 4217 1 4218 #else 4219 0 4220 #endif 4221 }, 4222 {"printer", 4223 #ifdef FEAT_PRINTER 4224 1 4225 #else 4226 0 4227 #endif 4228 }, 4229 {"profile", 4230 #ifdef FEAT_PROFILE 4231 1 4232 #else 4233 0 4234 #endif 4235 }, 4236 {"reltime", 4237 #ifdef FEAT_RELTIME 4238 1 4239 #else 4240 0 4241 #endif 4242 }, 4243 {"quickfix", 4244 #ifdef FEAT_QUICKFIX 4245 1 4246 #else 4247 0 4248 #endif 4249 }, 4250 {"rightleft", 4251 #ifdef FEAT_RIGHTLEFT 4252 1 4253 #else 4254 0 4255 #endif 4256 }, 4257 {"ruby", 4258 #if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY) 4259 1 4260 #else 4261 0 4262 #endif 4263 }, 4264 {"scrollbind", 1}, 4265 {"showcmd", 4266 #ifdef FEAT_CMDL_INFO 4267 1 4268 #else 4269 0 4270 #endif 4271 }, 4272 {"cmdline_info", 4273 #ifdef FEAT_CMDL_INFO 4274 1 4275 #else 4276 0 4277 #endif 4278 }, 4279 {"signs", 4280 #ifdef FEAT_SIGNS 4281 1 4282 #else 4283 0 4284 #endif 4285 }, 4286 {"smartindent", 4287 #ifdef FEAT_SMARTINDENT 4288 1 4289 #else 4290 0 4291 #endif 4292 }, 4293 {"startuptime", 4294 #ifdef STARTUPTIME 4295 1 4296 #else 4297 0 4298 #endif 4299 }, 4300 {"statusline", 4301 #ifdef FEAT_STL_OPT 4302 1 4303 #else 4304 0 4305 #endif 4306 }, 4307 {"netbeans_intg", 4308 #ifdef FEAT_NETBEANS_INTG 4309 1 4310 #else 4311 0 4312 #endif 4313 }, 4314 {"sound", 4315 #ifdef FEAT_SOUND 4316 1 4317 #else 4318 0 4319 #endif 4320 }, 4321 {"spell", 4322 #ifdef FEAT_SPELL 4323 1 4324 #else 4325 0 4326 #endif 4327 }, 4328 {"syntax", 4329 #ifdef FEAT_SYN_HL 4330 1 4331 #else 4332 0 4333 #endif 4334 }, 4335 {"system", 4336 #if defined(USE_SYSTEM) || !defined(UNIX) 4337 1 4338 #else 4339 0 4340 #endif 4341 }, 4342 {"tag_binary", 4343 #ifdef FEAT_TAG_BINS 4344 1 4345 #else 4346 0 4347 #endif 4348 }, 4349 {"tcl", 4350 #if defined(FEAT_TCL) && !defined(DYNAMIC_TCL) 4351 1 4352 #else 4353 0 4354 #endif 4355 }, 4356 {"termguicolors", 4357 #ifdef FEAT_TERMGUICOLORS 4358 1 4359 #else 4360 0 4361 #endif 4362 }, 4363 {"terminal", 4364 #if defined(FEAT_TERMINAL) && !defined(MSWIN) 4365 1 4366 #else 4367 0 4368 #endif 4369 }, 4370 {"terminfo", 4371 #ifdef TERMINFO 4372 1 4373 #else 4374 0 4375 #endif 4376 }, 4377 {"termresponse", 4378 #ifdef FEAT_TERMRESPONSE 4379 1 4380 #else 4381 0 4382 #endif 4383 }, 4384 {"textobjects", 4385 #ifdef FEAT_TEXTOBJ 4386 1 4387 #else 4388 0 4389 #endif 4390 }, 4391 {"textprop", 4392 #ifdef FEAT_PROP_POPUP 4393 1 4394 #else 4395 0 4396 #endif 4397 }, 4398 {"tgetent", 4399 #ifdef HAVE_TGETENT 4400 1 4401 #else 4402 0 4403 #endif 4404 }, 4405 {"timers", 4406 #ifdef FEAT_TIMERS 4407 1 4408 #else 4409 0 4410 #endif 4411 }, 4412 {"title", 4413 #ifdef FEAT_TITLE 4414 1 4415 #else 4416 0 4417 #endif 4418 }, 4419 {"toolbar", 4420 #ifdef FEAT_TOOLBAR 4421 1 4422 #else 4423 0 4424 #endif 4425 }, 4426 {"unnamedplus", 4427 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11) 4428 1 4429 #else 4430 0 4431 #endif 4432 }, 4433 {"user-commands", 1}, // was accidentally included in 5.4 4434 {"user_commands", 1}, 4435 {"vartabs", 4436 #ifdef FEAT_VARTABS 4437 1 4438 #else 4439 0 4440 #endif 4441 }, 4442 {"vertsplit", 1}, 4443 {"viminfo", 4444 #ifdef FEAT_VIMINFO 4445 1 4446 #else 4447 0 4448 #endif 4449 }, 4450 {"vimscript-1", 1}, 4451 {"vimscript-2", 1}, 4452 {"vimscript-3", 1}, 4453 {"vimscript-4", 1}, 4454 {"virtualedit", 1}, 4455 {"visual", 1}, 4456 {"visualextra", 1}, 4457 {"vreplace", 1}, 4458 {"vtp", 4459 #ifdef FEAT_VTP 4460 1 4461 #else 4462 0 4463 #endif 4464 }, 4465 {"wildignore", 4466 #ifdef FEAT_WILDIGN 4467 1 4468 #else 4469 0 4470 #endif 4471 }, 4472 {"wildmenu", 4473 #ifdef FEAT_WILDMENU 4474 1 4475 #else 4476 0 4477 #endif 4478 }, 4479 {"windows", 1}, 4480 {"winaltkeys", 4481 #ifdef FEAT_WAK 4482 1 4483 #else 4484 0 4485 #endif 4486 }, 4487 {"writebackup", 4488 #ifdef FEAT_WRITEBACKUP 4489 1 4490 #else 4491 0 4492 #endif 4493 }, 4494 {"xim", 4495 #ifdef FEAT_XIM 4496 1 4497 #else 4498 0 4499 #endif 4500 }, 4501 {"xfontset", 4502 #ifdef FEAT_XFONTSET 4503 1 4504 #else 4505 0 4506 #endif 4507 }, 4508 {"xpm", 4509 #if defined(FEAT_XPM_W32) || defined(HAVE_XPM) 4510 1 4511 #else 4512 0 4513 #endif 4514 }, 4515 {"xpm_w32", // for backward compatibility 4516 #ifdef FEAT_XPM_W32 4517 1 4518 #else 4519 0 4520 #endif 4521 }, 4522 {"xsmp", 4523 #ifdef USE_XSMP 4524 1 4525 #else 4526 0 4527 #endif 4528 }, 4529 {"xsmp_interact", 4530 #ifdef USE_XSMP_INTERACT 4531 1 4532 #else 4533 0 4534 #endif 4535 }, 4536 {"xterm_clipboard", 4537 #ifdef FEAT_XCLIPBOARD 4538 1 4539 #else 4540 0 4541 #endif 4542 }, 4543 {"xterm_save", 4544 #ifdef FEAT_XTERM_SAVE 4545 1 4546 #else 4547 0 4548 #endif 4549 }, 4550 {"X11", 4551 #if defined(UNIX) && defined(FEAT_X11) 4552 1 4553 #else 4554 0 4555 #endif 4556 }, 4557 {NULL, 0} 4558 }; 4559 4560 name = tv_get_string(&argvars[0]); 4561 for (i = 0; has_list[i].name != NULL; ++i) 4562 if (STRICMP(name, has_list[i].name) == 0) 4563 { 4564 x = TRUE; 4565 n = has_list[i].present; 4566 break; 4567 } 4568 4569 // features also in has_list[] but sometimes enabled at runtime 4570 if (x == TRUE && n == FALSE) 4571 { 4572 if (0) 4573 { 4574 // intentionally empty 4575 } 4576 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN) 4577 else if (STRICMP(name, "balloon_multiline") == 0) 4578 n = multiline_balloon_available(); 4579 #endif 4580 #ifdef VIMDLL 4581 else if (STRICMP(name, "filterpipe") == 0) 4582 n = gui.in_use || gui.starting; 4583 #endif 4584 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV) 4585 else if (STRICMP(name, "iconv") == 0) 4586 n = iconv_enabled(FALSE); 4587 #endif 4588 #ifdef DYNAMIC_LUA 4589 else if (STRICMP(name, "lua") == 0) 4590 n = lua_enabled(FALSE); 4591 #endif 4592 #ifdef DYNAMIC_MZSCHEME 4593 else if (STRICMP(name, "mzscheme") == 0) 4594 n = mzscheme_enabled(FALSE); 4595 #endif 4596 #ifdef DYNAMIC_PERL 4597 else if (STRICMP(name, "perl") == 0) 4598 n = perl_enabled(FALSE); 4599 #endif 4600 #ifdef DYNAMIC_PYTHON 4601 else if (STRICMP(name, "python") == 0) 4602 n = python_enabled(FALSE); 4603 #endif 4604 #ifdef DYNAMIC_PYTHON3 4605 else if (STRICMP(name, "python3") == 0) 4606 n = python3_enabled(FALSE); 4607 #endif 4608 #if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3) 4609 else if (STRICMP(name, "pythonx") == 0) 4610 { 4611 # if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3) 4612 if (p_pyx == 0) 4613 n = python3_enabled(FALSE) || python_enabled(FALSE); 4614 else if (p_pyx == 3) 4615 n = python3_enabled(FALSE); 4616 else if (p_pyx == 2) 4617 n = python_enabled(FALSE); 4618 # elif defined(DYNAMIC_PYTHON) 4619 n = python_enabled(FALSE); 4620 # elif defined(DYNAMIC_PYTHON3) 4621 n = python3_enabled(FALSE); 4622 # endif 4623 } 4624 #endif 4625 #ifdef DYNAMIC_RUBY 4626 else if (STRICMP(name, "ruby") == 0) 4627 n = ruby_enabled(FALSE); 4628 #endif 4629 #ifdef DYNAMIC_TCL 4630 else if (STRICMP(name, "tcl") == 0) 4631 n = tcl_enabled(FALSE); 4632 #endif 4633 #if defined(FEAT_TERMINAL) && defined(MSWIN) 4634 else if (STRICMP(name, "terminal") == 0) 4635 n = terminal_enabled(); 4636 #endif 4637 } 4638 4639 // features not in has_list[] 4640 if (x == FALSE) 4641 { 4642 if (STRNICMP(name, "patch", 5) == 0) 4643 { 4644 x = TRUE; 4645 if (name[5] == '-' 4646 && STRLEN(name) >= 11 4647 && vim_isdigit(name[6]) 4648 && vim_isdigit(name[8]) 4649 && vim_isdigit(name[10])) 4650 { 4651 int major = atoi((char *)name + 6); 4652 int minor = atoi((char *)name + 8); 4653 4654 // Expect "patch-9.9.01234". 4655 n = (major < VIM_VERSION_MAJOR 4656 || (major == VIM_VERSION_MAJOR 4657 && (minor < VIM_VERSION_MINOR 4658 || (minor == VIM_VERSION_MINOR 4659 && has_patch(atoi((char *)name + 10)))))); 4660 } 4661 else 4662 n = has_patch(atoi((char *)name + 5)); 4663 } 4664 else if (STRICMP(name, "vim_starting") == 0) 4665 { 4666 x = TRUE; 4667 n = (starting != 0); 4668 } 4669 else if (STRICMP(name, "ttyin") == 0) 4670 { 4671 x = TRUE; 4672 n = mch_input_isatty(); 4673 } 4674 else if (STRICMP(name, "ttyout") == 0) 4675 { 4676 x = TRUE; 4677 n = stdout_isatty; 4678 } 4679 else if (STRICMP(name, "multi_byte_encoding") == 0) 4680 { 4681 x = TRUE; 4682 n = has_mbyte; 4683 } 4684 else if (STRICMP(name, "gui_running") == 0) 4685 { 4686 x = TRUE; 4687 #ifdef FEAT_GUI 4688 n = (gui.in_use || gui.starting); 4689 #endif 4690 } 4691 else if (STRICMP(name, "browse") == 0) 4692 { 4693 x = TRUE; 4694 #if defined(FEAT_GUI) && defined(FEAT_BROWSE) 4695 n = gui.in_use; // gui_mch_browse() works when GUI is running 4696 #endif 4697 } 4698 else if (STRICMP(name, "syntax_items") == 0) 4699 { 4700 x = TRUE; 4701 #ifdef FEAT_SYN_HL 4702 n = syntax_present(curwin); 4703 #endif 4704 } 4705 else if (STRICMP(name, "vcon") == 0) 4706 { 4707 x = TRUE; 4708 #ifdef FEAT_VTP 4709 n = is_term_win32() && has_vtp_working(); 4710 #endif 4711 } 4712 else if (STRICMP(name, "netbeans_enabled") == 0) 4713 { 4714 x = TRUE; 4715 #ifdef FEAT_NETBEANS_INTG 4716 n = netbeans_active(); 4717 #endif 4718 } 4719 else if (STRICMP(name, "mouse_gpm_enabled") == 0) 4720 { 4721 x = TRUE; 4722 #ifdef FEAT_MOUSE_GPM 4723 n = gpm_enabled(); 4724 #endif 4725 } 4726 else if (STRICMP(name, "conpty") == 0) 4727 { 4728 x = TRUE; 4729 #if defined(FEAT_TERMINAL) && defined(MSWIN) 4730 n = use_conpty(); 4731 #endif 4732 } 4733 else if (STRICMP(name, "clipboard_working") == 0) 4734 { 4735 x = TRUE; 4736 #ifdef FEAT_CLIPBOARD 4737 n = clip_star.available; 4738 #endif 4739 } 4740 } 4741 4742 if (argvars[1].v_type != VAR_UNKNOWN && tv_get_number(&argvars[1]) != 0) 4743 // return whether feature could ever be enabled 4744 rettv->vval.v_number = x; 4745 else 4746 // return whether feature is enabled 4747 rettv->vval.v_number = n; 4748 } 4749 4750 /* 4751 * "haslocaldir()" function 4752 */ 4753 static void 4754 f_haslocaldir(typval_T *argvars, typval_T *rettv) 4755 { 4756 tabpage_T *tp = NULL; 4757 win_T *wp = NULL; 4758 4759 wp = find_tabwin(&argvars[0], &argvars[1], &tp); 4760 4761 // Check for window-local and tab-local directories 4762 if (wp != NULL && wp->w_localdir != NULL) 4763 rettv->vval.v_number = 1; 4764 else if (tp != NULL && tp->tp_localdir != NULL) 4765 rettv->vval.v_number = 2; 4766 else 4767 rettv->vval.v_number = 0; 4768 } 4769 4770 /* 4771 * "hasmapto()" function 4772 */ 4773 static void 4774 f_hasmapto(typval_T *argvars, typval_T *rettv) 4775 { 4776 char_u *name; 4777 char_u *mode; 4778 char_u buf[NUMBUFLEN]; 4779 int abbr = FALSE; 4780 4781 name = tv_get_string(&argvars[0]); 4782 if (argvars[1].v_type == VAR_UNKNOWN) 4783 mode = (char_u *)"nvo"; 4784 else 4785 { 4786 mode = tv_get_string_buf(&argvars[1], buf); 4787 if (argvars[2].v_type != VAR_UNKNOWN) 4788 abbr = (int)tv_get_number(&argvars[2]); 4789 } 4790 4791 if (map_to_exists(name, mode, abbr)) 4792 rettv->vval.v_number = TRUE; 4793 else 4794 rettv->vval.v_number = FALSE; 4795 } 4796 4797 /* 4798 * "highlightID(name)" function 4799 */ 4800 static void 4801 f_hlID(typval_T *argvars, typval_T *rettv) 4802 { 4803 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0])); 4804 } 4805 4806 /* 4807 * "highlight_exists()" function 4808 */ 4809 static void 4810 f_hlexists(typval_T *argvars, typval_T *rettv) 4811 { 4812 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0])); 4813 } 4814 4815 /* 4816 * "hostname()" function 4817 */ 4818 static void 4819 f_hostname(typval_T *argvars UNUSED, typval_T *rettv) 4820 { 4821 char_u hostname[256]; 4822 4823 mch_get_host_name(hostname, 256); 4824 rettv->v_type = VAR_STRING; 4825 rettv->vval.v_string = vim_strsave(hostname); 4826 } 4827 4828 /* 4829 * iconv() function 4830 */ 4831 static void 4832 f_iconv(typval_T *argvars UNUSED, typval_T *rettv) 4833 { 4834 char_u buf1[NUMBUFLEN]; 4835 char_u buf2[NUMBUFLEN]; 4836 char_u *from, *to, *str; 4837 vimconv_T vimconv; 4838 4839 rettv->v_type = VAR_STRING; 4840 rettv->vval.v_string = NULL; 4841 4842 str = tv_get_string(&argvars[0]); 4843 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1))); 4844 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2))); 4845 vimconv.vc_type = CONV_NONE; 4846 convert_setup(&vimconv, from, to); 4847 4848 // If the encodings are equal, no conversion needed. 4849 if (vimconv.vc_type == CONV_NONE) 4850 rettv->vval.v_string = vim_strsave(str); 4851 else 4852 rettv->vval.v_string = string_convert(&vimconv, str, NULL); 4853 4854 convert_setup(&vimconv, NULL, NULL); 4855 vim_free(from); 4856 vim_free(to); 4857 } 4858 4859 /* 4860 * "index()" function 4861 */ 4862 static void 4863 f_index(typval_T *argvars, typval_T *rettv) 4864 { 4865 list_T *l; 4866 listitem_T *item; 4867 blob_T *b; 4868 long idx = 0; 4869 int ic = FALSE; 4870 int error = FALSE; 4871 4872 rettv->vval.v_number = -1; 4873 if (argvars[0].v_type == VAR_BLOB) 4874 { 4875 typval_T tv; 4876 int start = 0; 4877 4878 if (argvars[2].v_type != VAR_UNKNOWN) 4879 { 4880 start = tv_get_number_chk(&argvars[2], &error); 4881 if (error) 4882 return; 4883 } 4884 b = argvars[0].vval.v_blob; 4885 if (b == NULL) 4886 return; 4887 if (start < 0) 4888 { 4889 start = blob_len(b) + start; 4890 if (start < 0) 4891 start = 0; 4892 } 4893 4894 for (idx = start; idx < blob_len(b); ++idx) 4895 { 4896 tv.v_type = VAR_NUMBER; 4897 tv.vval.v_number = blob_get(b, idx); 4898 if (tv_equal(&tv, &argvars[1], ic, FALSE)) 4899 { 4900 rettv->vval.v_number = idx; 4901 return; 4902 } 4903 } 4904 return; 4905 } 4906 else if (argvars[0].v_type != VAR_LIST) 4907 { 4908 emsg(_(e_listblobreq)); 4909 return; 4910 } 4911 4912 l = argvars[0].vval.v_list; 4913 if (l != NULL) 4914 { 4915 CHECK_LIST_MATERIALIZE(l); 4916 item = l->lv_first; 4917 if (argvars[2].v_type != VAR_UNKNOWN) 4918 { 4919 // Start at specified item. Use the cached index that list_find() 4920 // sets, so that a negative number also works. 4921 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error)); 4922 idx = l->lv_u.mat.lv_idx; 4923 if (argvars[3].v_type != VAR_UNKNOWN) 4924 ic = (int)tv_get_number_chk(&argvars[3], &error); 4925 if (error) 4926 item = NULL; 4927 } 4928 4929 for ( ; item != NULL; item = item->li_next, ++idx) 4930 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE)) 4931 { 4932 rettv->vval.v_number = idx; 4933 break; 4934 } 4935 } 4936 } 4937 4938 static int inputsecret_flag = 0; 4939 4940 /* 4941 * "input()" function 4942 * Also handles inputsecret() when inputsecret is set. 4943 */ 4944 static void 4945 f_input(typval_T *argvars, typval_T *rettv) 4946 { 4947 get_user_input(argvars, rettv, FALSE, inputsecret_flag); 4948 } 4949 4950 /* 4951 * "inputdialog()" function 4952 */ 4953 static void 4954 f_inputdialog(typval_T *argvars, typval_T *rettv) 4955 { 4956 #if defined(FEAT_GUI_TEXTDIALOG) 4957 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' 4958 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL) 4959 { 4960 char_u *message; 4961 char_u buf[NUMBUFLEN]; 4962 char_u *defstr = (char_u *)""; 4963 4964 message = tv_get_string_chk(&argvars[0]); 4965 if (argvars[1].v_type != VAR_UNKNOWN 4966 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL) 4967 vim_strncpy(IObuff, defstr, IOSIZE - 1); 4968 else 4969 IObuff[0] = NUL; 4970 if (message != NULL && defstr != NULL 4971 && do_dialog(VIM_QUESTION, NULL, message, 4972 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1) 4973 rettv->vval.v_string = vim_strsave(IObuff); 4974 else 4975 { 4976 if (message != NULL && defstr != NULL 4977 && argvars[1].v_type != VAR_UNKNOWN 4978 && argvars[2].v_type != VAR_UNKNOWN) 4979 rettv->vval.v_string = vim_strsave( 4980 tv_get_string_buf(&argvars[2], buf)); 4981 else 4982 rettv->vval.v_string = NULL; 4983 } 4984 rettv->v_type = VAR_STRING; 4985 } 4986 else 4987 #endif 4988 get_user_input(argvars, rettv, TRUE, inputsecret_flag); 4989 } 4990 4991 /* 4992 * "inputlist()" function 4993 */ 4994 static void 4995 f_inputlist(typval_T *argvars, typval_T *rettv) 4996 { 4997 list_T *l; 4998 listitem_T *li; 4999 int selected; 5000 int mouse_used; 5001 5002 #ifdef NO_CONSOLE_INPUT 5003 // While starting up, there is no place to enter text. When running tests 5004 // with --not-a-term we assume feedkeys() will be used. 5005 if (no_console_input() && !is_not_a_term()) 5006 return; 5007 #endif 5008 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL) 5009 { 5010 semsg(_(e_listarg), "inputlist()"); 5011 return; 5012 } 5013 5014 msg_start(); 5015 msg_row = Rows - 1; // for when 'cmdheight' > 1 5016 lines_left = Rows; // avoid more prompt 5017 msg_scroll = TRUE; 5018 msg_clr_eos(); 5019 5020 l = argvars[0].vval.v_list; 5021 CHECK_LIST_MATERIALIZE(l); 5022 FOR_ALL_LIST_ITEMS(l, li) 5023 { 5024 msg_puts((char *)tv_get_string(&li->li_tv)); 5025 msg_putchar('\n'); 5026 } 5027 5028 // Ask for choice. 5029 selected = prompt_for_number(&mouse_used); 5030 if (mouse_used) 5031 selected -= lines_left; 5032 5033 rettv->vval.v_number = selected; 5034 } 5035 5036 static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL}; 5037 5038 /* 5039 * "inputrestore()" function 5040 */ 5041 static void 5042 f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv) 5043 { 5044 if (ga_userinput.ga_len > 0) 5045 { 5046 --ga_userinput.ga_len; 5047 restore_typeahead((tasave_T *)(ga_userinput.ga_data) 5048 + ga_userinput.ga_len); 5049 // default return is zero == OK 5050 } 5051 else if (p_verbose > 1) 5052 { 5053 verb_msg(_("called inputrestore() more often than inputsave()")); 5054 rettv->vval.v_number = 1; // Failed 5055 } 5056 } 5057 5058 /* 5059 * "inputsave()" function 5060 */ 5061 static void 5062 f_inputsave(typval_T *argvars UNUSED, typval_T *rettv) 5063 { 5064 // Add an entry to the stack of typeahead storage. 5065 if (ga_grow(&ga_userinput, 1) == OK) 5066 { 5067 save_typeahead((tasave_T *)(ga_userinput.ga_data) 5068 + ga_userinput.ga_len); 5069 ++ga_userinput.ga_len; 5070 // default return is zero == OK 5071 } 5072 else 5073 rettv->vval.v_number = 1; // Failed 5074 } 5075 5076 /* 5077 * "inputsecret()" function 5078 */ 5079 static void 5080 f_inputsecret(typval_T *argvars, typval_T *rettv) 5081 { 5082 ++cmdline_star; 5083 ++inputsecret_flag; 5084 f_input(argvars, rettv); 5085 --cmdline_star; 5086 --inputsecret_flag; 5087 } 5088 5089 /* 5090 * "interrupt()" function 5091 */ 5092 static void 5093 f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 5094 { 5095 got_int = TRUE; 5096 } 5097 5098 /* 5099 * "invert(expr)" function 5100 */ 5101 static void 5102 f_invert(typval_T *argvars, typval_T *rettv) 5103 { 5104 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL); 5105 } 5106 5107 /* 5108 * Return TRUE if typeval "tv" is locked: Either that value is locked itself 5109 * or it refers to a List or Dictionary that is locked. 5110 */ 5111 static int 5112 tv_islocked(typval_T *tv) 5113 { 5114 return (tv->v_lock & VAR_LOCKED) 5115 || (tv->v_type == VAR_LIST 5116 && tv->vval.v_list != NULL 5117 && (tv->vval.v_list->lv_lock & VAR_LOCKED)) 5118 || (tv->v_type == VAR_DICT 5119 && tv->vval.v_dict != NULL 5120 && (tv->vval.v_dict->dv_lock & VAR_LOCKED)); 5121 } 5122 5123 /* 5124 * "islocked()" function 5125 */ 5126 static void 5127 f_islocked(typval_T *argvars, typval_T *rettv) 5128 { 5129 lval_T lv; 5130 char_u *end; 5131 dictitem_T *di; 5132 5133 rettv->vval.v_number = -1; 5134 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE, 5135 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START); 5136 if (end != NULL && lv.ll_name != NULL) 5137 { 5138 if (*end != NUL) 5139 emsg(_(e_trailing)); 5140 else 5141 { 5142 if (lv.ll_tv == NULL) 5143 { 5144 di = find_var(lv.ll_name, NULL, TRUE); 5145 if (di != NULL) 5146 { 5147 // Consider a variable locked when: 5148 // 1. the variable itself is locked 5149 // 2. the value of the variable is locked. 5150 // 3. the List or Dict value is locked. 5151 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK) 5152 || tv_islocked(&di->di_tv)); 5153 } 5154 } 5155 else if (lv.ll_range) 5156 emsg(_("E786: Range not allowed")); 5157 else if (lv.ll_newkey != NULL) 5158 semsg(_(e_dictkey), lv.ll_newkey); 5159 else if (lv.ll_list != NULL) 5160 // List item. 5161 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv); 5162 else 5163 // Dictionary item. 5164 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv); 5165 } 5166 } 5167 5168 clear_lval(&lv); 5169 } 5170 5171 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) 5172 /* 5173 * "isinf()" function 5174 */ 5175 static void 5176 f_isinf(typval_T *argvars, typval_T *rettv) 5177 { 5178 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float)) 5179 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1; 5180 } 5181 5182 /* 5183 * "isnan()" function 5184 */ 5185 static void 5186 f_isnan(typval_T *argvars, typval_T *rettv) 5187 { 5188 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT 5189 && isnan(argvars[0].vval.v_float); 5190 } 5191 #endif 5192 5193 /* 5194 * "last_buffer_nr()" function. 5195 */ 5196 static void 5197 f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv) 5198 { 5199 int n = 0; 5200 buf_T *buf; 5201 5202 FOR_ALL_BUFFERS(buf) 5203 if (n < buf->b_fnum) 5204 n = buf->b_fnum; 5205 5206 rettv->vval.v_number = n; 5207 } 5208 5209 /* 5210 * "len()" function 5211 */ 5212 static void 5213 f_len(typval_T *argvars, typval_T *rettv) 5214 { 5215 switch (argvars[0].v_type) 5216 { 5217 case VAR_STRING: 5218 case VAR_NUMBER: 5219 rettv->vval.v_number = (varnumber_T)STRLEN( 5220 tv_get_string(&argvars[0])); 5221 break; 5222 case VAR_BLOB: 5223 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob); 5224 break; 5225 case VAR_LIST: 5226 rettv->vval.v_number = list_len(argvars[0].vval.v_list); 5227 break; 5228 case VAR_DICT: 5229 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict); 5230 break; 5231 case VAR_UNKNOWN: 5232 case VAR_ANY: 5233 case VAR_VOID: 5234 case VAR_BOOL: 5235 case VAR_SPECIAL: 5236 case VAR_FLOAT: 5237 case VAR_FUNC: 5238 case VAR_PARTIAL: 5239 case VAR_JOB: 5240 case VAR_CHANNEL: 5241 emsg(_("E701: Invalid type for len()")); 5242 break; 5243 } 5244 } 5245 5246 static void 5247 libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type) 5248 { 5249 #ifdef FEAT_LIBCALL 5250 char_u *string_in; 5251 char_u **string_result; 5252 int nr_result; 5253 #endif 5254 5255 rettv->v_type = type; 5256 if (type != VAR_NUMBER) 5257 rettv->vval.v_string = NULL; 5258 5259 if (check_restricted() || check_secure()) 5260 return; 5261 5262 #ifdef FEAT_LIBCALL 5263 // The first two args must be strings, otherwise it's meaningless 5264 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING) 5265 { 5266 string_in = NULL; 5267 if (argvars[2].v_type == VAR_STRING) 5268 string_in = argvars[2].vval.v_string; 5269 if (type == VAR_NUMBER) 5270 string_result = NULL; 5271 else 5272 string_result = &rettv->vval.v_string; 5273 if (mch_libcall(argvars[0].vval.v_string, 5274 argvars[1].vval.v_string, 5275 string_in, 5276 argvars[2].vval.v_number, 5277 string_result, 5278 &nr_result) == OK 5279 && type == VAR_NUMBER) 5280 rettv->vval.v_number = nr_result; 5281 } 5282 #endif 5283 } 5284 5285 /* 5286 * "libcall()" function 5287 */ 5288 static void 5289 f_libcall(typval_T *argvars, typval_T *rettv) 5290 { 5291 libcall_common(argvars, rettv, VAR_STRING); 5292 } 5293 5294 /* 5295 * "libcallnr()" function 5296 */ 5297 static void 5298 f_libcallnr(typval_T *argvars, typval_T *rettv) 5299 { 5300 libcall_common(argvars, rettv, VAR_NUMBER); 5301 } 5302 5303 /* 5304 * "line(string, [winid])" function 5305 */ 5306 static void 5307 f_line(typval_T *argvars, typval_T *rettv) 5308 { 5309 linenr_T lnum = 0; 5310 pos_T *fp = NULL; 5311 int fnum; 5312 int id; 5313 tabpage_T *tp; 5314 win_T *wp; 5315 win_T *save_curwin; 5316 tabpage_T *save_curtab; 5317 5318 if (argvars[1].v_type != VAR_UNKNOWN) 5319 { 5320 // use window specified in the second argument 5321 id = (int)tv_get_number(&argvars[1]); 5322 wp = win_id2wp_tp(id, &tp); 5323 if (wp != NULL && tp != NULL) 5324 { 5325 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) 5326 == OK) 5327 { 5328 check_cursor(); 5329 fp = var2fpos(&argvars[0], TRUE, &fnum); 5330 } 5331 restore_win_noblock(save_curwin, save_curtab, TRUE); 5332 } 5333 } 5334 else 5335 // use current window 5336 fp = var2fpos(&argvars[0], TRUE, &fnum); 5337 5338 if (fp != NULL) 5339 lnum = fp->lnum; 5340 rettv->vval.v_number = lnum; 5341 } 5342 5343 /* 5344 * "line2byte(lnum)" function 5345 */ 5346 static void 5347 f_line2byte(typval_T *argvars UNUSED, typval_T *rettv) 5348 { 5349 #ifndef FEAT_BYTEOFF 5350 rettv->vval.v_number = -1; 5351 #else 5352 linenr_T lnum; 5353 5354 lnum = tv_get_lnum(argvars); 5355 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) 5356 rettv->vval.v_number = -1; 5357 else 5358 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL); 5359 if (rettv->vval.v_number >= 0) 5360 ++rettv->vval.v_number; 5361 #endif 5362 } 5363 5364 #ifdef FEAT_FLOAT 5365 /* 5366 * "log()" function 5367 */ 5368 static void 5369 f_log(typval_T *argvars, typval_T *rettv) 5370 { 5371 float_T f = 0.0; 5372 5373 rettv->v_type = VAR_FLOAT; 5374 if (get_float_arg(argvars, &f) == OK) 5375 rettv->vval.v_float = log(f); 5376 else 5377 rettv->vval.v_float = 0.0; 5378 } 5379 5380 /* 5381 * "log10()" function 5382 */ 5383 static void 5384 f_log10(typval_T *argvars, typval_T *rettv) 5385 { 5386 float_T f = 0.0; 5387 5388 rettv->v_type = VAR_FLOAT; 5389 if (get_float_arg(argvars, &f) == OK) 5390 rettv->vval.v_float = log10(f); 5391 else 5392 rettv->vval.v_float = 0.0; 5393 } 5394 #endif 5395 5396 #ifdef FEAT_LUA 5397 /* 5398 * "luaeval()" function 5399 */ 5400 static void 5401 f_luaeval(typval_T *argvars, typval_T *rettv) 5402 { 5403 char_u *str; 5404 char_u buf[NUMBUFLEN]; 5405 5406 if (check_restricted() || check_secure()) 5407 return; 5408 5409 str = tv_get_string_buf(&argvars[0], buf); 5410 do_luaeval(str, argvars + 1, rettv); 5411 } 5412 #endif 5413 5414 /* 5415 * "maparg()" function 5416 */ 5417 static void 5418 f_maparg(typval_T *argvars, typval_T *rettv) 5419 { 5420 get_maparg(argvars, rettv, TRUE); 5421 } 5422 5423 /* 5424 * "mapcheck()" function 5425 */ 5426 static void 5427 f_mapcheck(typval_T *argvars, typval_T *rettv) 5428 { 5429 get_maparg(argvars, rettv, FALSE); 5430 } 5431 5432 typedef enum 5433 { 5434 MATCH_END, // matchend() 5435 MATCH_MATCH, // match() 5436 MATCH_STR, // matchstr() 5437 MATCH_LIST, // matchlist() 5438 MATCH_POS // matchstrpos() 5439 } matchtype_T; 5440 5441 static void 5442 find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type) 5443 { 5444 char_u *str = NULL; 5445 long len = 0; 5446 char_u *expr = NULL; 5447 char_u *pat; 5448 regmatch_T regmatch; 5449 char_u patbuf[NUMBUFLEN]; 5450 char_u strbuf[NUMBUFLEN]; 5451 char_u *save_cpo; 5452 long start = 0; 5453 long nth = 1; 5454 colnr_T startcol = 0; 5455 int match = 0; 5456 list_T *l = NULL; 5457 listitem_T *li = NULL; 5458 long idx = 0; 5459 char_u *tofree = NULL; 5460 5461 // Make 'cpoptions' empty, the 'l' flag should not be used here. 5462 save_cpo = p_cpo; 5463 p_cpo = (char_u *)""; 5464 5465 rettv->vval.v_number = -1; 5466 if (type == MATCH_LIST || type == MATCH_POS) 5467 { 5468 // type MATCH_LIST: return empty list when there are no matches. 5469 // type MATCH_POS: return ["", -1, -1, -1] 5470 if (rettv_list_alloc(rettv) == FAIL) 5471 goto theend; 5472 if (type == MATCH_POS 5473 && (list_append_string(rettv->vval.v_list, 5474 (char_u *)"", 0) == FAIL 5475 || list_append_number(rettv->vval.v_list, 5476 (varnumber_T)-1) == FAIL 5477 || list_append_number(rettv->vval.v_list, 5478 (varnumber_T)-1) == FAIL 5479 || list_append_number(rettv->vval.v_list, 5480 (varnumber_T)-1) == FAIL)) 5481 { 5482 list_free(rettv->vval.v_list); 5483 rettv->vval.v_list = NULL; 5484 goto theend; 5485 } 5486 } 5487 else if (type == MATCH_STR) 5488 { 5489 rettv->v_type = VAR_STRING; 5490 rettv->vval.v_string = NULL; 5491 } 5492 5493 if (argvars[0].v_type == VAR_LIST) 5494 { 5495 if ((l = argvars[0].vval.v_list) == NULL) 5496 goto theend; 5497 CHECK_LIST_MATERIALIZE(l); 5498 li = l->lv_first; 5499 } 5500 else 5501 { 5502 expr = str = tv_get_string(&argvars[0]); 5503 len = (long)STRLEN(str); 5504 } 5505 5506 pat = tv_get_string_buf_chk(&argvars[1], patbuf); 5507 if (pat == NULL) 5508 goto theend; 5509 5510 if (argvars[2].v_type != VAR_UNKNOWN) 5511 { 5512 int error = FALSE; 5513 5514 start = (long)tv_get_number_chk(&argvars[2], &error); 5515 if (error) 5516 goto theend; 5517 if (l != NULL) 5518 { 5519 li = list_find(l, start); 5520 if (li == NULL) 5521 goto theend; 5522 idx = l->lv_u.mat.lv_idx; // use the cached index 5523 } 5524 else 5525 { 5526 if (start < 0) 5527 start = 0; 5528 if (start > len) 5529 goto theend; 5530 // When "count" argument is there ignore matches before "start", 5531 // otherwise skip part of the string. Differs when pattern is "^" 5532 // or "\<". 5533 if (argvars[3].v_type != VAR_UNKNOWN) 5534 startcol = start; 5535 else 5536 { 5537 str += start; 5538 len -= start; 5539 } 5540 } 5541 5542 if (argvars[3].v_type != VAR_UNKNOWN) 5543 nth = (long)tv_get_number_chk(&argvars[3], &error); 5544 if (error) 5545 goto theend; 5546 } 5547 5548 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); 5549 if (regmatch.regprog != NULL) 5550 { 5551 regmatch.rm_ic = p_ic; 5552 5553 for (;;) 5554 { 5555 if (l != NULL) 5556 { 5557 if (li == NULL) 5558 { 5559 match = FALSE; 5560 break; 5561 } 5562 vim_free(tofree); 5563 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0); 5564 if (str == NULL) 5565 break; 5566 } 5567 5568 match = vim_regexec_nl(®match, str, (colnr_T)startcol); 5569 5570 if (match && --nth <= 0) 5571 break; 5572 if (l == NULL && !match) 5573 break; 5574 5575 // Advance to just after the match. 5576 if (l != NULL) 5577 { 5578 li = li->li_next; 5579 ++idx; 5580 } 5581 else 5582 { 5583 startcol = (colnr_T)(regmatch.startp[0] 5584 + (*mb_ptr2len)(regmatch.startp[0]) - str); 5585 if (startcol > (colnr_T)len 5586 || str + startcol <= regmatch.startp[0]) 5587 { 5588 match = FALSE; 5589 break; 5590 } 5591 } 5592 } 5593 5594 if (match) 5595 { 5596 if (type == MATCH_POS) 5597 { 5598 listitem_T *li1 = rettv->vval.v_list->lv_first; 5599 listitem_T *li2 = li1->li_next; 5600 listitem_T *li3 = li2->li_next; 5601 listitem_T *li4 = li3->li_next; 5602 5603 vim_free(li1->li_tv.vval.v_string); 5604 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0], 5605 (int)(regmatch.endp[0] - regmatch.startp[0])); 5606 li3->li_tv.vval.v_number = 5607 (varnumber_T)(regmatch.startp[0] - expr); 5608 li4->li_tv.vval.v_number = 5609 (varnumber_T)(regmatch.endp[0] - expr); 5610 if (l != NULL) 5611 li2->li_tv.vval.v_number = (varnumber_T)idx; 5612 } 5613 else if (type == MATCH_LIST) 5614 { 5615 int i; 5616 5617 // return list with matched string and submatches 5618 for (i = 0; i < NSUBEXP; ++i) 5619 { 5620 if (regmatch.endp[i] == NULL) 5621 { 5622 if (list_append_string(rettv->vval.v_list, 5623 (char_u *)"", 0) == FAIL) 5624 break; 5625 } 5626 else if (list_append_string(rettv->vval.v_list, 5627 regmatch.startp[i], 5628 (int)(regmatch.endp[i] - regmatch.startp[i])) 5629 == FAIL) 5630 break; 5631 } 5632 } 5633 else if (type == MATCH_STR) 5634 { 5635 // return matched string 5636 if (l != NULL) 5637 copy_tv(&li->li_tv, rettv); 5638 else 5639 rettv->vval.v_string = vim_strnsave(regmatch.startp[0], 5640 (int)(regmatch.endp[0] - regmatch.startp[0])); 5641 } 5642 else if (l != NULL) 5643 rettv->vval.v_number = idx; 5644 else 5645 { 5646 if (type != MATCH_END) 5647 rettv->vval.v_number = 5648 (varnumber_T)(regmatch.startp[0] - str); 5649 else 5650 rettv->vval.v_number = 5651 (varnumber_T)(regmatch.endp[0] - str); 5652 rettv->vval.v_number += (varnumber_T)(str - expr); 5653 } 5654 } 5655 vim_regfree(regmatch.regprog); 5656 } 5657 5658 theend: 5659 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL) 5660 // matchstrpos() without a list: drop the second item. 5661 listitem_remove(rettv->vval.v_list, 5662 rettv->vval.v_list->lv_first->li_next); 5663 vim_free(tofree); 5664 p_cpo = save_cpo; 5665 } 5666 5667 /* 5668 * "match()" function 5669 */ 5670 static void 5671 f_match(typval_T *argvars, typval_T *rettv) 5672 { 5673 find_some_match(argvars, rettv, MATCH_MATCH); 5674 } 5675 5676 /* 5677 * "matchend()" function 5678 */ 5679 static void 5680 f_matchend(typval_T *argvars, typval_T *rettv) 5681 { 5682 find_some_match(argvars, rettv, MATCH_END); 5683 } 5684 5685 /* 5686 * "matchlist()" function 5687 */ 5688 static void 5689 f_matchlist(typval_T *argvars, typval_T *rettv) 5690 { 5691 find_some_match(argvars, rettv, MATCH_LIST); 5692 } 5693 5694 /* 5695 * "matchstr()" function 5696 */ 5697 static void 5698 f_matchstr(typval_T *argvars, typval_T *rettv) 5699 { 5700 find_some_match(argvars, rettv, MATCH_STR); 5701 } 5702 5703 /* 5704 * "matchstrpos()" function 5705 */ 5706 static void 5707 f_matchstrpos(typval_T *argvars, typval_T *rettv) 5708 { 5709 find_some_match(argvars, rettv, MATCH_POS); 5710 } 5711 5712 static void 5713 max_min(typval_T *argvars, typval_T *rettv, int domax) 5714 { 5715 varnumber_T n = 0; 5716 varnumber_T i; 5717 int error = FALSE; 5718 5719 if (argvars[0].v_type == VAR_LIST) 5720 { 5721 list_T *l; 5722 listitem_T *li; 5723 5724 l = argvars[0].vval.v_list; 5725 if (l != NULL && l->lv_len > 0) 5726 { 5727 if (l->lv_first == &range_list_item) 5728 { 5729 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax) 5730 n = l->lv_u.nonmat.lv_start; 5731 else 5732 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1) 5733 * l->lv_u.nonmat.lv_stride; 5734 } 5735 else 5736 { 5737 li = l->lv_first; 5738 if (li != NULL) 5739 { 5740 n = tv_get_number_chk(&li->li_tv, &error); 5741 for (;;) 5742 { 5743 li = li->li_next; 5744 if (li == NULL) 5745 break; 5746 i = tv_get_number_chk(&li->li_tv, &error); 5747 if (domax ? i > n : i < n) 5748 n = i; 5749 } 5750 } 5751 } 5752 } 5753 } 5754 else if (argvars[0].v_type == VAR_DICT) 5755 { 5756 dict_T *d; 5757 int first = TRUE; 5758 hashitem_T *hi; 5759 int todo; 5760 5761 d = argvars[0].vval.v_dict; 5762 if (d != NULL) 5763 { 5764 todo = (int)d->dv_hashtab.ht_used; 5765 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) 5766 { 5767 if (!HASHITEM_EMPTY(hi)) 5768 { 5769 --todo; 5770 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error); 5771 if (first) 5772 { 5773 n = i; 5774 first = FALSE; 5775 } 5776 else if (domax ? i > n : i < n) 5777 n = i; 5778 } 5779 } 5780 } 5781 } 5782 else 5783 semsg(_(e_listdictarg), domax ? "max()" : "min()"); 5784 rettv->vval.v_number = error ? 0 : n; 5785 } 5786 5787 /* 5788 * "max()" function 5789 */ 5790 static void 5791 f_max(typval_T *argvars, typval_T *rettv) 5792 { 5793 max_min(argvars, rettv, TRUE); 5794 } 5795 5796 /* 5797 * "min()" function 5798 */ 5799 static void 5800 f_min(typval_T *argvars, typval_T *rettv) 5801 { 5802 max_min(argvars, rettv, FALSE); 5803 } 5804 5805 #if defined(FEAT_MZSCHEME) || defined(PROTO) 5806 /* 5807 * "mzeval()" function 5808 */ 5809 static void 5810 f_mzeval(typval_T *argvars, typval_T *rettv) 5811 { 5812 char_u *str; 5813 char_u buf[NUMBUFLEN]; 5814 5815 if (check_restricted() || check_secure()) 5816 return; 5817 str = tv_get_string_buf(&argvars[0], buf); 5818 do_mzeval(str, rettv); 5819 } 5820 5821 void 5822 mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv) 5823 { 5824 typval_T argvars[3]; 5825 5826 argvars[0].v_type = VAR_STRING; 5827 argvars[0].vval.v_string = name; 5828 copy_tv(args, &argvars[1]); 5829 argvars[2].v_type = VAR_UNKNOWN; 5830 f_call(argvars, rettv); 5831 clear_tv(&argvars[1]); 5832 } 5833 #endif 5834 5835 /* 5836 * "nextnonblank()" function 5837 */ 5838 static void 5839 f_nextnonblank(typval_T *argvars, typval_T *rettv) 5840 { 5841 linenr_T lnum; 5842 5843 for (lnum = tv_get_lnum(argvars); ; ++lnum) 5844 { 5845 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count) 5846 { 5847 lnum = 0; 5848 break; 5849 } 5850 if (*skipwhite(ml_get(lnum)) != NUL) 5851 break; 5852 } 5853 rettv->vval.v_number = lnum; 5854 } 5855 5856 /* 5857 * "nr2char()" function 5858 */ 5859 static void 5860 f_nr2char(typval_T *argvars, typval_T *rettv) 5861 { 5862 char_u buf[NUMBUFLEN]; 5863 5864 if (has_mbyte) 5865 { 5866 int utf8 = 0; 5867 5868 if (argvars[1].v_type != VAR_UNKNOWN) 5869 utf8 = (int)tv_get_number_chk(&argvars[1], NULL); 5870 if (utf8) 5871 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL; 5872 else 5873 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL; 5874 } 5875 else 5876 { 5877 buf[0] = (char_u)tv_get_number(&argvars[0]); 5878 buf[1] = NUL; 5879 } 5880 rettv->v_type = VAR_STRING; 5881 rettv->vval.v_string = vim_strsave(buf); 5882 } 5883 5884 /* 5885 * "or(expr, expr)" function 5886 */ 5887 static void 5888 f_or(typval_T *argvars, typval_T *rettv) 5889 { 5890 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL) 5891 | tv_get_number_chk(&argvars[1], NULL); 5892 } 5893 5894 #ifdef FEAT_PERL 5895 /* 5896 * "perleval()" function 5897 */ 5898 static void 5899 f_perleval(typval_T *argvars, typval_T *rettv) 5900 { 5901 char_u *str; 5902 char_u buf[NUMBUFLEN]; 5903 5904 str = tv_get_string_buf(&argvars[0], buf); 5905 do_perleval(str, rettv); 5906 } 5907 #endif 5908 5909 #ifdef FEAT_FLOAT 5910 /* 5911 * "pow()" function 5912 */ 5913 static void 5914 f_pow(typval_T *argvars, typval_T *rettv) 5915 { 5916 float_T fx = 0.0, fy = 0.0; 5917 5918 rettv->v_type = VAR_FLOAT; 5919 if (get_float_arg(argvars, &fx) == OK 5920 && get_float_arg(&argvars[1], &fy) == OK) 5921 rettv->vval.v_float = pow(fx, fy); 5922 else 5923 rettv->vval.v_float = 0.0; 5924 } 5925 #endif 5926 5927 /* 5928 * "prevnonblank()" function 5929 */ 5930 static void 5931 f_prevnonblank(typval_T *argvars, typval_T *rettv) 5932 { 5933 linenr_T lnum; 5934 5935 lnum = tv_get_lnum(argvars); 5936 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) 5937 lnum = 0; 5938 else 5939 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL) 5940 --lnum; 5941 rettv->vval.v_number = lnum; 5942 } 5943 5944 // This dummy va_list is here because: 5945 // - passing a NULL pointer doesn't work when va_list isn't a pointer 5946 // - locally in the function results in a "used before set" warning 5947 // - using va_start() to initialize it gives "function with fixed args" error 5948 static va_list ap; 5949 5950 /* 5951 * "printf()" function 5952 */ 5953 static void 5954 f_printf(typval_T *argvars, typval_T *rettv) 5955 { 5956 char_u buf[NUMBUFLEN]; 5957 int len; 5958 char_u *s; 5959 int saved_did_emsg = did_emsg; 5960 char *fmt; 5961 5962 rettv->v_type = VAR_STRING; 5963 rettv->vval.v_string = NULL; 5964 5965 // Get the required length, allocate the buffer and do it for real. 5966 did_emsg = FALSE; 5967 fmt = (char *)tv_get_string_buf(&argvars[0], buf); 5968 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1); 5969 if (!did_emsg) 5970 { 5971 s = alloc(len + 1); 5972 if (s != NULL) 5973 { 5974 rettv->vval.v_string = s; 5975 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt, 5976 ap, argvars + 1); 5977 } 5978 } 5979 did_emsg |= saved_did_emsg; 5980 } 5981 5982 /* 5983 * "pum_getpos()" function 5984 */ 5985 static void 5986 f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 5987 { 5988 if (rettv_dict_alloc(rettv) != OK) 5989 return; 5990 pum_set_event_info(rettv->vval.v_dict); 5991 } 5992 5993 /* 5994 * "pumvisible()" function 5995 */ 5996 static void 5997 f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 5998 { 5999 if (pum_visible()) 6000 rettv->vval.v_number = 1; 6001 } 6002 6003 #ifdef FEAT_PYTHON3 6004 /* 6005 * "py3eval()" function 6006 */ 6007 static void 6008 f_py3eval(typval_T *argvars, typval_T *rettv) 6009 { 6010 char_u *str; 6011 char_u buf[NUMBUFLEN]; 6012 6013 if (check_restricted() || check_secure()) 6014 return; 6015 6016 if (p_pyx == 0) 6017 p_pyx = 3; 6018 6019 str = tv_get_string_buf(&argvars[0], buf); 6020 do_py3eval(str, rettv); 6021 } 6022 #endif 6023 6024 #ifdef FEAT_PYTHON 6025 /* 6026 * "pyeval()" function 6027 */ 6028 static void 6029 f_pyeval(typval_T *argvars, typval_T *rettv) 6030 { 6031 char_u *str; 6032 char_u buf[NUMBUFLEN]; 6033 6034 if (check_restricted() || check_secure()) 6035 return; 6036 6037 if (p_pyx == 0) 6038 p_pyx = 2; 6039 6040 str = tv_get_string_buf(&argvars[0], buf); 6041 do_pyeval(str, rettv); 6042 } 6043 #endif 6044 6045 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) 6046 /* 6047 * "pyxeval()" function 6048 */ 6049 static void 6050 f_pyxeval(typval_T *argvars, typval_T *rettv) 6051 { 6052 if (check_restricted() || check_secure()) 6053 return; 6054 6055 # if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3) 6056 init_pyxversion(); 6057 if (p_pyx == 2) 6058 f_pyeval(argvars, rettv); 6059 else 6060 f_py3eval(argvars, rettv); 6061 # elif defined(FEAT_PYTHON) 6062 f_pyeval(argvars, rettv); 6063 # elif defined(FEAT_PYTHON3) 6064 f_py3eval(argvars, rettv); 6065 # endif 6066 } 6067 #endif 6068 6069 static UINT32_T srand_seed_for_testing = 0; 6070 static int srand_seed_for_testing_is_used = FALSE; 6071 6072 static void 6073 f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED) 6074 { 6075 if (argvars[0].v_type == VAR_UNKNOWN) 6076 srand_seed_for_testing_is_used = FALSE; 6077 else 6078 { 6079 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]); 6080 srand_seed_for_testing_is_used = TRUE; 6081 } 6082 } 6083 6084 static void 6085 init_srand(UINT32_T *x) 6086 { 6087 #ifndef MSWIN 6088 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried 6089 #endif 6090 6091 if (srand_seed_for_testing_is_used) 6092 { 6093 *x = srand_seed_for_testing; 6094 return; 6095 } 6096 #ifndef MSWIN 6097 if (dev_urandom_state != FAIL) 6098 { 6099 int fd = open("/dev/urandom", O_RDONLY); 6100 struct { 6101 union { 6102 UINT32_T number; 6103 char bytes[sizeof(UINT32_T)]; 6104 } contents; 6105 } buf; 6106 6107 // Attempt reading /dev/urandom. 6108 if (fd == -1) 6109 dev_urandom_state = FAIL; 6110 else 6111 { 6112 buf.contents.number = 0; 6113 if (read(fd, buf.contents.bytes, sizeof(UINT32_T)) 6114 != sizeof(UINT32_T)) 6115 dev_urandom_state = FAIL; 6116 else 6117 { 6118 dev_urandom_state = OK; 6119 *x = buf.contents.number; 6120 } 6121 close(fd); 6122 } 6123 } 6124 if (dev_urandom_state != OK) 6125 // Reading /dev/urandom doesn't work, fall back to time(). 6126 #endif 6127 *x = vim_time(); 6128 } 6129 6130 #define ROTL(x, k) ((x << k) | (x >> (32 - k))) 6131 #define SPLITMIX32(x, z) ( \ 6132 z = (x += 0x9e3779b9), \ 6133 z = (z ^ (z >> 16)) * 0x85ebca6b, \ 6134 z = (z ^ (z >> 13)) * 0xc2b2ae35, \ 6135 z ^ (z >> 16) \ 6136 ) 6137 #define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \ 6138 result = ROTL(y * 5, 7) * 9; \ 6139 t = y << 9; \ 6140 z ^= x; \ 6141 w ^= y; \ 6142 y ^= z, x ^= w; \ 6143 z ^= t; \ 6144 w = ROTL(w, 11); 6145 6146 /* 6147 * "rand()" function 6148 */ 6149 static void 6150 f_rand(typval_T *argvars, typval_T *rettv) 6151 { 6152 list_T *l = NULL; 6153 static UINT32_T gx, gy, gz, gw; 6154 static int initialized = FALSE; 6155 listitem_T *lx, *ly, *lz, *lw; 6156 UINT32_T x, y, z, w, t, result; 6157 6158 if (argvars[0].v_type == VAR_UNKNOWN) 6159 { 6160 // When no argument is given use the global seed list. 6161 if (initialized == FALSE) 6162 { 6163 // Initialize the global seed list. 6164 init_srand(&x); 6165 6166 gx = SPLITMIX32(x, z); 6167 gy = SPLITMIX32(x, z); 6168 gz = SPLITMIX32(x, z); 6169 gw = SPLITMIX32(x, z); 6170 initialized = TRUE; 6171 } 6172 6173 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw); 6174 } 6175 else if (argvars[0].v_type == VAR_LIST) 6176 { 6177 l = argvars[0].vval.v_list; 6178 if (l == NULL || list_len(l) != 4) 6179 goto theend; 6180 6181 lx = list_find(l, 0L); 6182 ly = list_find(l, 1L); 6183 lz = list_find(l, 2L); 6184 lw = list_find(l, 3L); 6185 if (lx->li_tv.v_type != VAR_NUMBER) goto theend; 6186 if (ly->li_tv.v_type != VAR_NUMBER) goto theend; 6187 if (lz->li_tv.v_type != VAR_NUMBER) goto theend; 6188 if (lw->li_tv.v_type != VAR_NUMBER) goto theend; 6189 x = (UINT32_T)lx->li_tv.vval.v_number; 6190 y = (UINT32_T)ly->li_tv.vval.v_number; 6191 z = (UINT32_T)lz->li_tv.vval.v_number; 6192 w = (UINT32_T)lw->li_tv.vval.v_number; 6193 6194 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w); 6195 6196 lx->li_tv.vval.v_number = (varnumber_T)x; 6197 ly->li_tv.vval.v_number = (varnumber_T)y; 6198 lz->li_tv.vval.v_number = (varnumber_T)z; 6199 lw->li_tv.vval.v_number = (varnumber_T)w; 6200 } 6201 else 6202 goto theend; 6203 6204 rettv->v_type = VAR_NUMBER; 6205 rettv->vval.v_number = (varnumber_T)result; 6206 return; 6207 6208 theend: 6209 semsg(_(e_invarg2), tv_get_string(&argvars[0])); 6210 rettv->v_type = VAR_NUMBER; 6211 rettv->vval.v_number = -1; 6212 } 6213 6214 /* 6215 * "srand()" function 6216 */ 6217 static void 6218 f_srand(typval_T *argvars, typval_T *rettv) 6219 { 6220 UINT32_T x = 0, z; 6221 6222 if (rettv_list_alloc(rettv) == FAIL) 6223 return; 6224 if (argvars[0].v_type == VAR_UNKNOWN) 6225 { 6226 init_srand(&x); 6227 } 6228 else 6229 { 6230 int error = FALSE; 6231 6232 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error); 6233 if (error) 6234 return; 6235 } 6236 6237 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z)); 6238 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z)); 6239 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z)); 6240 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z)); 6241 } 6242 6243 #undef ROTL 6244 #undef SPLITMIX32 6245 #undef SHUFFLE_XOSHIRO128STARSTAR 6246 6247 /* 6248 * "range()" function 6249 */ 6250 static void 6251 f_range(typval_T *argvars, typval_T *rettv) 6252 { 6253 varnumber_T start; 6254 varnumber_T end; 6255 varnumber_T stride = 1; 6256 int error = FALSE; 6257 6258 start = tv_get_number_chk(&argvars[0], &error); 6259 if (argvars[1].v_type == VAR_UNKNOWN) 6260 { 6261 end = start - 1; 6262 start = 0; 6263 } 6264 else 6265 { 6266 end = tv_get_number_chk(&argvars[1], &error); 6267 if (argvars[2].v_type != VAR_UNKNOWN) 6268 stride = tv_get_number_chk(&argvars[2], &error); 6269 } 6270 6271 if (error) 6272 return; // type error; errmsg already given 6273 if (stride == 0) 6274 emsg(_("E726: Stride is zero")); 6275 else if (stride > 0 ? end + 1 < start : end - 1 > start) 6276 emsg(_("E727: Start past end")); 6277 else if (rettv_list_alloc(rettv) == OK) 6278 { 6279 list_T *list = rettv->vval.v_list; 6280 6281 // Create a non-materialized list. This is much more efficient and 6282 // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must 6283 // be called. 6284 list->lv_first = &range_list_item; 6285 list->lv_u.nonmat.lv_start = start; 6286 list->lv_u.nonmat.lv_end = end; 6287 list->lv_u.nonmat.lv_stride = stride; 6288 list->lv_len = (end - start) / stride + 1; 6289 } 6290 } 6291 6292 /* 6293 * Materialize "list". 6294 * Do not call directly, use CHECK_LIST_MATERIALIZE() 6295 */ 6296 void 6297 range_list_materialize(list_T *list) 6298 { 6299 varnumber_T start = list->lv_u.nonmat.lv_start; 6300 varnumber_T end = list->lv_u.nonmat.lv_end; 6301 int stride = list->lv_u.nonmat.lv_stride; 6302 varnumber_T i; 6303 6304 list->lv_first = NULL; 6305 list->lv_u.mat.lv_last = NULL; 6306 list->lv_len = 0; 6307 list->lv_u.mat.lv_idx_item = NULL; 6308 for (i = start; stride > 0 ? i <= end : i >= end; i += stride) 6309 if (list_append_number(list, (varnumber_T)i) == FAIL) 6310 break; 6311 } 6312 6313 static void 6314 return_register(int regname, typval_T *rettv) 6315 { 6316 char_u buf[2] = {0, 0}; 6317 6318 buf[0] = (char_u)regname; 6319 rettv->v_type = VAR_STRING; 6320 rettv->vval.v_string = vim_strsave(buf); 6321 } 6322 6323 /* 6324 * "reg_executing()" function 6325 */ 6326 static void 6327 f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv) 6328 { 6329 return_register(reg_executing, rettv); 6330 } 6331 6332 /* 6333 * "reg_recording()" function 6334 */ 6335 static void 6336 f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv) 6337 { 6338 return_register(reg_recording, rettv); 6339 } 6340 6341 /* 6342 * "rename({from}, {to})" function 6343 */ 6344 static void 6345 f_rename(typval_T *argvars, typval_T *rettv) 6346 { 6347 char_u buf[NUMBUFLEN]; 6348 6349 if (check_restricted() || check_secure()) 6350 rettv->vval.v_number = -1; 6351 else 6352 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]), 6353 tv_get_string_buf(&argvars[1], buf)); 6354 } 6355 6356 /* 6357 * "repeat()" function 6358 */ 6359 static void 6360 f_repeat(typval_T *argvars, typval_T *rettv) 6361 { 6362 char_u *p; 6363 int n; 6364 int slen; 6365 int len; 6366 char_u *r; 6367 int i; 6368 6369 n = (int)tv_get_number(&argvars[1]); 6370 if (argvars[0].v_type == VAR_LIST) 6371 { 6372 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL) 6373 while (n-- > 0) 6374 if (list_extend(rettv->vval.v_list, 6375 argvars[0].vval.v_list, NULL) == FAIL) 6376 break; 6377 } 6378 else 6379 { 6380 p = tv_get_string(&argvars[0]); 6381 rettv->v_type = VAR_STRING; 6382 rettv->vval.v_string = NULL; 6383 6384 slen = (int)STRLEN(p); 6385 len = slen * n; 6386 if (len <= 0) 6387 return; 6388 6389 r = alloc(len + 1); 6390 if (r != NULL) 6391 { 6392 for (i = 0; i < n; i++) 6393 mch_memmove(r + i * slen, p, (size_t)slen); 6394 r[len] = NUL; 6395 } 6396 6397 rettv->vval.v_string = r; 6398 } 6399 } 6400 6401 #define SP_NOMOVE 0x01 // don't move cursor 6402 #define SP_REPEAT 0x02 // repeat to find outer pair 6403 #define SP_RETCOUNT 0x04 // return matchcount 6404 #define SP_SETPCMARK 0x08 // set previous context mark 6405 #define SP_START 0x10 // accept match at start position 6406 #define SP_SUBPAT 0x20 // return nr of matching sub-pattern 6407 #define SP_END 0x40 // leave cursor at end of match 6408 #define SP_COLUMN 0x80 // start at cursor column 6409 6410 /* 6411 * Get flags for a search function. 6412 * Possibly sets "p_ws". 6413 * Returns BACKWARD, FORWARD or zero (for an error). 6414 */ 6415 static int 6416 get_search_arg(typval_T *varp, int *flagsp) 6417 { 6418 int dir = FORWARD; 6419 char_u *flags; 6420 char_u nbuf[NUMBUFLEN]; 6421 int mask; 6422 6423 if (varp->v_type != VAR_UNKNOWN) 6424 { 6425 flags = tv_get_string_buf_chk(varp, nbuf); 6426 if (flags == NULL) 6427 return 0; // type error; errmsg already given 6428 while (*flags != NUL) 6429 { 6430 switch (*flags) 6431 { 6432 case 'b': dir = BACKWARD; break; 6433 case 'w': p_ws = TRUE; break; 6434 case 'W': p_ws = FALSE; break; 6435 default: mask = 0; 6436 if (flagsp != NULL) 6437 switch (*flags) 6438 { 6439 case 'c': mask = SP_START; break; 6440 case 'e': mask = SP_END; break; 6441 case 'm': mask = SP_RETCOUNT; break; 6442 case 'n': mask = SP_NOMOVE; break; 6443 case 'p': mask = SP_SUBPAT; break; 6444 case 'r': mask = SP_REPEAT; break; 6445 case 's': mask = SP_SETPCMARK; break; 6446 case 'z': mask = SP_COLUMN; break; 6447 } 6448 if (mask == 0) 6449 { 6450 semsg(_(e_invarg2), flags); 6451 dir = 0; 6452 } 6453 else 6454 *flagsp |= mask; 6455 } 6456 if (dir == 0) 6457 break; 6458 ++flags; 6459 } 6460 } 6461 return dir; 6462 } 6463 6464 /* 6465 * Shared by search() and searchpos() functions. 6466 */ 6467 static int 6468 search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) 6469 { 6470 int flags; 6471 char_u *pat; 6472 pos_T pos; 6473 pos_T save_cursor; 6474 int save_p_ws = p_ws; 6475 int dir; 6476 int retval = 0; // default: FAIL 6477 long lnum_stop = 0; 6478 #ifdef FEAT_RELTIME 6479 proftime_T tm; 6480 long time_limit = 0; 6481 #endif 6482 int options = SEARCH_KEEP; 6483 int subpatnum; 6484 searchit_arg_T sia; 6485 6486 pat = tv_get_string(&argvars[0]); 6487 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws 6488 if (dir == 0) 6489 goto theend; 6490 flags = *flagsp; 6491 if (flags & SP_START) 6492 options |= SEARCH_START; 6493 if (flags & SP_END) 6494 options |= SEARCH_END; 6495 if (flags & SP_COLUMN) 6496 options |= SEARCH_COL; 6497 6498 // Optional arguments: line number to stop searching and timeout. 6499 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) 6500 { 6501 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL); 6502 if (lnum_stop < 0) 6503 goto theend; 6504 #ifdef FEAT_RELTIME 6505 if (argvars[3].v_type != VAR_UNKNOWN) 6506 { 6507 time_limit = (long)tv_get_number_chk(&argvars[3], NULL); 6508 if (time_limit < 0) 6509 goto theend; 6510 } 6511 #endif 6512 } 6513 6514 #ifdef FEAT_RELTIME 6515 // Set the time limit, if there is one. 6516 profile_setlimit(time_limit, &tm); 6517 #endif 6518 6519 /* 6520 * This function does not accept SP_REPEAT and SP_RETCOUNT flags. 6521 * Check to make sure only those flags are set. 6522 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both 6523 * flags cannot be set. Check for that condition also. 6524 */ 6525 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0) 6526 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) 6527 { 6528 semsg(_(e_invarg2), tv_get_string(&argvars[1])); 6529 goto theend; 6530 } 6531 6532 pos = save_cursor = curwin->w_cursor; 6533 CLEAR_FIELD(sia); 6534 sia.sa_stop_lnum = (linenr_T)lnum_stop; 6535 #ifdef FEAT_RELTIME 6536 sia.sa_tm = &tm; 6537 #endif 6538 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L, 6539 options, RE_SEARCH, &sia); 6540 if (subpatnum != FAIL) 6541 { 6542 if (flags & SP_SUBPAT) 6543 retval = subpatnum; 6544 else 6545 retval = pos.lnum; 6546 if (flags & SP_SETPCMARK) 6547 setpcmark(); 6548 curwin->w_cursor = pos; 6549 if (match_pos != NULL) 6550 { 6551 // Store the match cursor position 6552 match_pos->lnum = pos.lnum; 6553 match_pos->col = pos.col + 1; 6554 } 6555 // "/$" will put the cursor after the end of the line, may need to 6556 // correct that here 6557 check_cursor(); 6558 } 6559 6560 // If 'n' flag is used: restore cursor position. 6561 if (flags & SP_NOMOVE) 6562 curwin->w_cursor = save_cursor; 6563 else 6564 curwin->w_set_curswant = TRUE; 6565 theend: 6566 p_ws = save_p_ws; 6567 6568 return retval; 6569 } 6570 6571 #ifdef FEAT_FLOAT 6572 6573 /* 6574 * round() is not in C90, use ceil() or floor() instead. 6575 */ 6576 float_T 6577 vim_round(float_T f) 6578 { 6579 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5); 6580 } 6581 6582 /* 6583 * "round({float})" function 6584 */ 6585 static void 6586 f_round(typval_T *argvars, typval_T *rettv) 6587 { 6588 float_T f = 0.0; 6589 6590 rettv->v_type = VAR_FLOAT; 6591 if (get_float_arg(argvars, &f) == OK) 6592 rettv->vval.v_float = vim_round(f); 6593 else 6594 rettv->vval.v_float = 0.0; 6595 } 6596 #endif 6597 6598 #ifdef FEAT_RUBY 6599 /* 6600 * "rubyeval()" function 6601 */ 6602 static void 6603 f_rubyeval(typval_T *argvars, typval_T *rettv) 6604 { 6605 char_u *str; 6606 char_u buf[NUMBUFLEN]; 6607 6608 str = tv_get_string_buf(&argvars[0], buf); 6609 do_rubyeval(str, rettv); 6610 } 6611 #endif 6612 6613 /* 6614 * "screenattr()" function 6615 */ 6616 static void 6617 f_screenattr(typval_T *argvars, typval_T *rettv) 6618 { 6619 int row; 6620 int col; 6621 int c; 6622 6623 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1; 6624 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1; 6625 if (row < 0 || row >= screen_Rows 6626 || col < 0 || col >= screen_Columns) 6627 c = -1; 6628 else 6629 c = ScreenAttrs[LineOffset[row] + col]; 6630 rettv->vval.v_number = c; 6631 } 6632 6633 /* 6634 * "screenchar()" function 6635 */ 6636 static void 6637 f_screenchar(typval_T *argvars, typval_T *rettv) 6638 { 6639 int row; 6640 int col; 6641 int off; 6642 int c; 6643 6644 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1; 6645 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1; 6646 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns) 6647 c = -1; 6648 else 6649 { 6650 off = LineOffset[row] + col; 6651 if (enc_utf8 && ScreenLinesUC[off] != 0) 6652 c = ScreenLinesUC[off]; 6653 else 6654 c = ScreenLines[off]; 6655 } 6656 rettv->vval.v_number = c; 6657 } 6658 6659 /* 6660 * "screenchars()" function 6661 */ 6662 static void 6663 f_screenchars(typval_T *argvars, typval_T *rettv) 6664 { 6665 int row; 6666 int col; 6667 int off; 6668 int c; 6669 int i; 6670 6671 if (rettv_list_alloc(rettv) == FAIL) 6672 return; 6673 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1; 6674 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1; 6675 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns) 6676 return; 6677 6678 off = LineOffset[row] + col; 6679 if (enc_utf8 && ScreenLinesUC[off] != 0) 6680 c = ScreenLinesUC[off]; 6681 else 6682 c = ScreenLines[off]; 6683 list_append_number(rettv->vval.v_list, (varnumber_T)c); 6684 6685 if (enc_utf8) 6686 6687 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i) 6688 list_append_number(rettv->vval.v_list, 6689 (varnumber_T)ScreenLinesC[i][off]); 6690 } 6691 6692 /* 6693 * "screencol()" function 6694 * 6695 * First column is 1 to be consistent with virtcol(). 6696 */ 6697 static void 6698 f_screencol(typval_T *argvars UNUSED, typval_T *rettv) 6699 { 6700 rettv->vval.v_number = screen_screencol() + 1; 6701 } 6702 6703 /* 6704 * "screenrow()" function 6705 */ 6706 static void 6707 f_screenrow(typval_T *argvars UNUSED, typval_T *rettv) 6708 { 6709 rettv->vval.v_number = screen_screenrow() + 1; 6710 } 6711 6712 /* 6713 * "screenstring()" function 6714 */ 6715 static void 6716 f_screenstring(typval_T *argvars, typval_T *rettv) 6717 { 6718 int row; 6719 int col; 6720 int off; 6721 int c; 6722 int i; 6723 char_u buf[MB_MAXBYTES + 1]; 6724 int buflen = 0; 6725 6726 rettv->vval.v_string = NULL; 6727 rettv->v_type = VAR_STRING; 6728 6729 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1; 6730 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1; 6731 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns) 6732 return; 6733 6734 off = LineOffset[row] + col; 6735 if (enc_utf8 && ScreenLinesUC[off] != 0) 6736 c = ScreenLinesUC[off]; 6737 else 6738 c = ScreenLines[off]; 6739 buflen += mb_char2bytes(c, buf); 6740 6741 if (enc_utf8) 6742 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i) 6743 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen); 6744 6745 buf[buflen] = NUL; 6746 rettv->vval.v_string = vim_strsave(buf); 6747 } 6748 6749 /* 6750 * "search()" function 6751 */ 6752 static void 6753 f_search(typval_T *argvars, typval_T *rettv) 6754 { 6755 int flags = 0; 6756 6757 rettv->vval.v_number = search_cmn(argvars, NULL, &flags); 6758 } 6759 6760 /* 6761 * "searchdecl()" function 6762 */ 6763 static void 6764 f_searchdecl(typval_T *argvars, typval_T *rettv) 6765 { 6766 int locally = 1; 6767 int thisblock = 0; 6768 int error = FALSE; 6769 char_u *name; 6770 6771 rettv->vval.v_number = 1; // default: FAIL 6772 6773 name = tv_get_string_chk(&argvars[0]); 6774 if (argvars[1].v_type != VAR_UNKNOWN) 6775 { 6776 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0; 6777 if (!error && argvars[2].v_type != VAR_UNKNOWN) 6778 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0; 6779 } 6780 if (!error && name != NULL) 6781 rettv->vval.v_number = find_decl(name, (int)STRLEN(name), 6782 locally, thisblock, SEARCH_KEEP) == FAIL; 6783 } 6784 6785 /* 6786 * Used by searchpair() and searchpairpos() 6787 */ 6788 static int 6789 searchpair_cmn(typval_T *argvars, pos_T *match_pos) 6790 { 6791 char_u *spat, *mpat, *epat; 6792 typval_T *skip; 6793 int save_p_ws = p_ws; 6794 int dir; 6795 int flags = 0; 6796 char_u nbuf1[NUMBUFLEN]; 6797 char_u nbuf2[NUMBUFLEN]; 6798 int retval = 0; // default: FAIL 6799 long lnum_stop = 0; 6800 long time_limit = 0; 6801 6802 // Get the three pattern arguments: start, middle, end. Will result in an 6803 // error if not a valid argument. 6804 spat = tv_get_string_chk(&argvars[0]); 6805 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1); 6806 epat = tv_get_string_buf_chk(&argvars[2], nbuf2); 6807 if (spat == NULL || mpat == NULL || epat == NULL) 6808 goto theend; // type error 6809 6810 // Handle the optional fourth argument: flags 6811 dir = get_search_arg(&argvars[3], &flags); // may set p_ws 6812 if (dir == 0) 6813 goto theend; 6814 6815 // Don't accept SP_END or SP_SUBPAT. 6816 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set. 6817 if ((flags & (SP_END | SP_SUBPAT)) != 0 6818 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) 6819 { 6820 semsg(_(e_invarg2), tv_get_string(&argvars[3])); 6821 goto theend; 6822 } 6823 6824 // Using 'r' implies 'W', otherwise it doesn't work. 6825 if (flags & SP_REPEAT) 6826 p_ws = FALSE; 6827 6828 // Optional fifth argument: skip expression 6829 if (argvars[3].v_type == VAR_UNKNOWN 6830 || argvars[4].v_type == VAR_UNKNOWN) 6831 skip = NULL; 6832 else 6833 { 6834 skip = &argvars[4]; 6835 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL 6836 && skip->v_type != VAR_STRING) 6837 { 6838 // Type error 6839 semsg(_(e_invarg2), tv_get_string(&argvars[4])); 6840 goto theend; 6841 } 6842 if (argvars[5].v_type != VAR_UNKNOWN) 6843 { 6844 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL); 6845 if (lnum_stop < 0) 6846 { 6847 semsg(_(e_invarg2), tv_get_string(&argvars[5])); 6848 goto theend; 6849 } 6850 #ifdef FEAT_RELTIME 6851 if (argvars[6].v_type != VAR_UNKNOWN) 6852 { 6853 time_limit = (long)tv_get_number_chk(&argvars[6], NULL); 6854 if (time_limit < 0) 6855 { 6856 semsg(_(e_invarg2), tv_get_string(&argvars[6])); 6857 goto theend; 6858 } 6859 } 6860 #endif 6861 } 6862 } 6863 6864 retval = do_searchpair(spat, mpat, epat, dir, skip, flags, 6865 match_pos, lnum_stop, time_limit); 6866 6867 theend: 6868 p_ws = save_p_ws; 6869 6870 return retval; 6871 } 6872 6873 /* 6874 * "searchpair()" function 6875 */ 6876 static void 6877 f_searchpair(typval_T *argvars, typval_T *rettv) 6878 { 6879 rettv->vval.v_number = searchpair_cmn(argvars, NULL); 6880 } 6881 6882 /* 6883 * "searchpairpos()" function 6884 */ 6885 static void 6886 f_searchpairpos(typval_T *argvars, typval_T *rettv) 6887 { 6888 pos_T match_pos; 6889 int lnum = 0; 6890 int col = 0; 6891 6892 if (rettv_list_alloc(rettv) == FAIL) 6893 return; 6894 6895 if (searchpair_cmn(argvars, &match_pos) > 0) 6896 { 6897 lnum = match_pos.lnum; 6898 col = match_pos.col; 6899 } 6900 6901 list_append_number(rettv->vval.v_list, (varnumber_T)lnum); 6902 list_append_number(rettv->vval.v_list, (varnumber_T)col); 6903 } 6904 6905 /* 6906 * Search for a start/middle/end thing. 6907 * Used by searchpair(), see its documentation for the details. 6908 * Returns 0 or -1 for no match, 6909 */ 6910 long 6911 do_searchpair( 6912 char_u *spat, // start pattern 6913 char_u *mpat, // middle pattern 6914 char_u *epat, // end pattern 6915 int dir, // BACKWARD or FORWARD 6916 typval_T *skip, // skip expression 6917 int flags, // SP_SETPCMARK and other SP_ values 6918 pos_T *match_pos, 6919 linenr_T lnum_stop, // stop at this line if not zero 6920 long time_limit UNUSED) // stop after this many msec 6921 { 6922 char_u *save_cpo; 6923 char_u *pat, *pat2 = NULL, *pat3 = NULL; 6924 long retval = 0; 6925 pos_T pos; 6926 pos_T firstpos; 6927 pos_T foundpos; 6928 pos_T save_cursor; 6929 pos_T save_pos; 6930 int n; 6931 int r; 6932 int nest = 1; 6933 int use_skip = FALSE; 6934 int err; 6935 int options = SEARCH_KEEP; 6936 #ifdef FEAT_RELTIME 6937 proftime_T tm; 6938 #endif 6939 6940 // Make 'cpoptions' empty, the 'l' flag should not be used here. 6941 save_cpo = p_cpo; 6942 p_cpo = empty_option; 6943 6944 #ifdef FEAT_RELTIME 6945 // Set the time limit, if there is one. 6946 profile_setlimit(time_limit, &tm); 6947 #endif 6948 6949 // Make two search patterns: start/end (pat2, for in nested pairs) and 6950 // start/middle/end (pat3, for the top pair). 6951 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17); 6952 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25); 6953 if (pat2 == NULL || pat3 == NULL) 6954 goto theend; 6955 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat); 6956 if (*mpat == NUL) 6957 STRCPY(pat3, pat2); 6958 else 6959 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", 6960 spat, epat, mpat); 6961 if (flags & SP_START) 6962 options |= SEARCH_START; 6963 6964 if (skip != NULL) 6965 { 6966 // Empty string means to not use the skip expression. 6967 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC) 6968 use_skip = skip->vval.v_string != NULL 6969 && *skip->vval.v_string != NUL; 6970 } 6971 6972 save_cursor = curwin->w_cursor; 6973 pos = curwin->w_cursor; 6974 CLEAR_POS(&firstpos); 6975 CLEAR_POS(&foundpos); 6976 pat = pat3; 6977 for (;;) 6978 { 6979 searchit_arg_T sia; 6980 6981 CLEAR_FIELD(sia); 6982 sia.sa_stop_lnum = lnum_stop; 6983 #ifdef FEAT_RELTIME 6984 sia.sa_tm = &tm; 6985 #endif 6986 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L, 6987 options, RE_SEARCH, &sia); 6988 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))) 6989 // didn't find it or found the first match again: FAIL 6990 break; 6991 6992 if (firstpos.lnum == 0) 6993 firstpos = pos; 6994 if (EQUAL_POS(pos, foundpos)) 6995 { 6996 // Found the same position again. Can happen with a pattern that 6997 // has "\zs" at the end and searching backwards. Advance one 6998 // character and try again. 6999 if (dir == BACKWARD) 7000 decl(&pos); 7001 else 7002 incl(&pos); 7003 } 7004 foundpos = pos; 7005 7006 // clear the start flag to avoid getting stuck here 7007 options &= ~SEARCH_START; 7008 7009 // If the skip pattern matches, ignore this match. 7010 if (use_skip) 7011 { 7012 save_pos = curwin->w_cursor; 7013 curwin->w_cursor = pos; 7014 err = FALSE; 7015 r = eval_expr_to_bool(skip, &err); 7016 curwin->w_cursor = save_pos; 7017 if (err) 7018 { 7019 // Evaluating {skip} caused an error, break here. 7020 curwin->w_cursor = save_cursor; 7021 retval = -1; 7022 break; 7023 } 7024 if (r) 7025 continue; 7026 } 7027 7028 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2)) 7029 { 7030 // Found end when searching backwards or start when searching 7031 // forward: nested pair. 7032 ++nest; 7033 pat = pat2; // nested, don't search for middle 7034 } 7035 else 7036 { 7037 // Found end when searching forward or start when searching 7038 // backward: end of (nested) pair; or found middle in outer pair. 7039 if (--nest == 1) 7040 pat = pat3; // outer level, search for middle 7041 } 7042 7043 if (nest == 0) 7044 { 7045 // Found the match: return matchcount or line number. 7046 if (flags & SP_RETCOUNT) 7047 ++retval; 7048 else 7049 retval = pos.lnum; 7050 if (flags & SP_SETPCMARK) 7051 setpcmark(); 7052 curwin->w_cursor = pos; 7053 if (!(flags & SP_REPEAT)) 7054 break; 7055 nest = 1; // search for next unmatched 7056 } 7057 } 7058 7059 if (match_pos != NULL) 7060 { 7061 // Store the match cursor position 7062 match_pos->lnum = curwin->w_cursor.lnum; 7063 match_pos->col = curwin->w_cursor.col + 1; 7064 } 7065 7066 // If 'n' flag is used or search failed: restore cursor position. 7067 if ((flags & SP_NOMOVE) || retval == 0) 7068 curwin->w_cursor = save_cursor; 7069 7070 theend: 7071 vim_free(pat2); 7072 vim_free(pat3); 7073 if (p_cpo == empty_option) 7074 p_cpo = save_cpo; 7075 else 7076 // Darn, evaluating the {skip} expression changed the value. 7077 free_string_option(save_cpo); 7078 7079 return retval; 7080 } 7081 7082 /* 7083 * "searchpos()" function 7084 */ 7085 static void 7086 f_searchpos(typval_T *argvars, typval_T *rettv) 7087 { 7088 pos_T match_pos; 7089 int lnum = 0; 7090 int col = 0; 7091 int n; 7092 int flags = 0; 7093 7094 if (rettv_list_alloc(rettv) == FAIL) 7095 return; 7096 7097 n = search_cmn(argvars, &match_pos, &flags); 7098 if (n > 0) 7099 { 7100 lnum = match_pos.lnum; 7101 col = match_pos.col; 7102 } 7103 7104 list_append_number(rettv->vval.v_list, (varnumber_T)lnum); 7105 list_append_number(rettv->vval.v_list, (varnumber_T)col); 7106 if (flags & SP_SUBPAT) 7107 list_append_number(rettv->vval.v_list, (varnumber_T)n); 7108 } 7109 7110 static void 7111 f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED) 7112 { 7113 dict_T *d; 7114 dictitem_T *di; 7115 char_u *csearch; 7116 7117 if (argvars[0].v_type != VAR_DICT) 7118 { 7119 emsg(_(e_dictreq)); 7120 return; 7121 } 7122 7123 if ((d = argvars[0].vval.v_dict) != NULL) 7124 { 7125 csearch = dict_get_string(d, (char_u *)"char", FALSE); 7126 if (csearch != NULL) 7127 { 7128 if (enc_utf8) 7129 { 7130 int pcc[MAX_MCO]; 7131 int c = utfc_ptr2char(csearch, pcc); 7132 7133 set_last_csearch(c, csearch, utfc_ptr2len(csearch)); 7134 } 7135 else 7136 set_last_csearch(PTR2CHAR(csearch), 7137 csearch, mb_ptr2len(csearch)); 7138 } 7139 7140 di = dict_find(d, (char_u *)"forward", -1); 7141 if (di != NULL) 7142 set_csearch_direction((int)tv_get_number(&di->di_tv) 7143 ? FORWARD : BACKWARD); 7144 7145 di = dict_find(d, (char_u *)"until", -1); 7146 if (di != NULL) 7147 set_csearch_until(!!tv_get_number(&di->di_tv)); 7148 } 7149 } 7150 7151 /* 7152 * "setenv()" function 7153 */ 7154 static void 7155 f_setenv(typval_T *argvars, typval_T *rettv UNUSED) 7156 { 7157 char_u namebuf[NUMBUFLEN]; 7158 char_u valbuf[NUMBUFLEN]; 7159 char_u *name = tv_get_string_buf(&argvars[0], namebuf); 7160 7161 if (argvars[1].v_type == VAR_SPECIAL 7162 && argvars[1].vval.v_number == VVAL_NULL) 7163 vim_unsetenv(name); 7164 else 7165 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf)); 7166 } 7167 7168 /* 7169 * "setfperm({fname}, {mode})" function 7170 */ 7171 static void 7172 f_setfperm(typval_T *argvars, typval_T *rettv) 7173 { 7174 char_u *fname; 7175 char_u modebuf[NUMBUFLEN]; 7176 char_u *mode_str; 7177 int i; 7178 int mask; 7179 int mode = 0; 7180 7181 rettv->vval.v_number = 0; 7182 fname = tv_get_string_chk(&argvars[0]); 7183 if (fname == NULL) 7184 return; 7185 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf); 7186 if (mode_str == NULL) 7187 return; 7188 if (STRLEN(mode_str) != 9) 7189 { 7190 semsg(_(e_invarg2), mode_str); 7191 return; 7192 } 7193 7194 mask = 1; 7195 for (i = 8; i >= 0; --i) 7196 { 7197 if (mode_str[i] != '-') 7198 mode |= mask; 7199 mask = mask << 1; 7200 } 7201 rettv->vval.v_number = mch_setperm(fname, mode) == OK; 7202 } 7203 7204 /* 7205 * "setpos()" function 7206 */ 7207 static void 7208 f_setpos(typval_T *argvars, typval_T *rettv) 7209 { 7210 pos_T pos; 7211 int fnum; 7212 char_u *name; 7213 colnr_T curswant = -1; 7214 7215 rettv->vval.v_number = -1; 7216 name = tv_get_string_chk(argvars); 7217 if (name != NULL) 7218 { 7219 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK) 7220 { 7221 if (pos.col != MAXCOL && --pos.col < 0) 7222 pos.col = 0; 7223 if (name[0] == '.' && name[1] == NUL) 7224 { 7225 // set cursor; "fnum" is ignored 7226 curwin->w_cursor = pos; 7227 if (curswant >= 0) 7228 { 7229 curwin->w_curswant = curswant - 1; 7230 curwin->w_set_curswant = FALSE; 7231 } 7232 check_cursor(); 7233 rettv->vval.v_number = 0; 7234 } 7235 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) 7236 { 7237 // set mark 7238 if (setmark_pos(name[1], &pos, fnum) == OK) 7239 rettv->vval.v_number = 0; 7240 } 7241 else 7242 emsg(_(e_invarg)); 7243 } 7244 } 7245 } 7246 7247 /* 7248 * "setreg()" function 7249 */ 7250 static void 7251 f_setreg(typval_T *argvars, typval_T *rettv) 7252 { 7253 int regname; 7254 char_u *strregname; 7255 char_u *stropt; 7256 char_u *strval; 7257 int append; 7258 char_u yank_type; 7259 long block_len; 7260 7261 block_len = -1; 7262 yank_type = MAUTO; 7263 append = FALSE; 7264 7265 strregname = tv_get_string_chk(argvars); 7266 rettv->vval.v_number = 1; // FAIL is default 7267 7268 if (strregname == NULL) 7269 return; // type error; errmsg already given 7270 regname = *strregname; 7271 if (regname == 0 || regname == '@') 7272 regname = '"'; 7273 7274 if (argvars[2].v_type != VAR_UNKNOWN) 7275 { 7276 stropt = tv_get_string_chk(&argvars[2]); 7277 if (stropt == NULL) 7278 return; // type error 7279 for (; *stropt != NUL; ++stropt) 7280 switch (*stropt) 7281 { 7282 case 'a': case 'A': // append 7283 append = TRUE; 7284 break; 7285 case 'v': case 'c': // character-wise selection 7286 yank_type = MCHAR; 7287 break; 7288 case 'V': case 'l': // line-wise selection 7289 yank_type = MLINE; 7290 break; 7291 case 'b': case Ctrl_V: // block-wise selection 7292 yank_type = MBLOCK; 7293 if (VIM_ISDIGIT(stropt[1])) 7294 { 7295 ++stropt; 7296 block_len = getdigits(&stropt) - 1; 7297 --stropt; 7298 } 7299 break; 7300 } 7301 } 7302 7303 if (argvars[1].v_type == VAR_LIST) 7304 { 7305 char_u **lstval; 7306 char_u **allocval; 7307 char_u buf[NUMBUFLEN]; 7308 char_u **curval; 7309 char_u **curallocval; 7310 list_T *ll = argvars[1].vval.v_list; 7311 listitem_T *li; 7312 int len; 7313 7314 // If the list is NULL handle like an empty list. 7315 len = ll == NULL ? 0 : ll->lv_len; 7316 7317 // First half: use for pointers to result lines; second half: use for 7318 // pointers to allocated copies. 7319 lstval = ALLOC_MULT(char_u *, (len + 1) * 2); 7320 if (lstval == NULL) 7321 return; 7322 curval = lstval; 7323 allocval = lstval + len + 2; 7324 curallocval = allocval; 7325 7326 if (ll != NULL) 7327 { 7328 CHECK_LIST_MATERIALIZE(ll); 7329 FOR_ALL_LIST_ITEMS(ll, li) 7330 { 7331 strval = tv_get_string_buf_chk(&li->li_tv, buf); 7332 if (strval == NULL) 7333 goto free_lstval; 7334 if (strval == buf) 7335 { 7336 // Need to make a copy, next tv_get_string_buf_chk() will 7337 // overwrite the string. 7338 strval = vim_strsave(buf); 7339 if (strval == NULL) 7340 goto free_lstval; 7341 *curallocval++ = strval; 7342 } 7343 *curval++ = strval; 7344 } 7345 } 7346 *curval++ = NULL; 7347 7348 write_reg_contents_lst(regname, lstval, -1, 7349 append, yank_type, block_len); 7350 free_lstval: 7351 while (curallocval > allocval) 7352 vim_free(*--curallocval); 7353 vim_free(lstval); 7354 } 7355 else 7356 { 7357 strval = tv_get_string_chk(&argvars[1]); 7358 if (strval == NULL) 7359 return; 7360 write_reg_contents_ex(regname, strval, -1, 7361 append, yank_type, block_len); 7362 } 7363 rettv->vval.v_number = 0; 7364 } 7365 7366 /* 7367 * "settagstack()" function 7368 */ 7369 static void 7370 f_settagstack(typval_T *argvars, typval_T *rettv) 7371 { 7372 static char *e_invact2 = N_("E962: Invalid action: '%s'"); 7373 win_T *wp; 7374 dict_T *d; 7375 int action = 'r'; 7376 7377 rettv->vval.v_number = -1; 7378 7379 // first argument: window number or id 7380 wp = find_win_by_nr_or_id(&argvars[0]); 7381 if (wp == NULL) 7382 return; 7383 7384 // second argument: dict with items to set in the tag stack 7385 if (argvars[1].v_type != VAR_DICT) 7386 { 7387 emsg(_(e_dictreq)); 7388 return; 7389 } 7390 d = argvars[1].vval.v_dict; 7391 if (d == NULL) 7392 return; 7393 7394 // third argument: action - 'a' for append and 'r' for replace. 7395 // default is to replace the stack. 7396 if (argvars[2].v_type == VAR_UNKNOWN) 7397 action = 'r'; 7398 else if (argvars[2].v_type == VAR_STRING) 7399 { 7400 char_u *actstr; 7401 actstr = tv_get_string_chk(&argvars[2]); 7402 if (actstr == NULL) 7403 return; 7404 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't') 7405 && actstr[1] == NUL) 7406 action = *actstr; 7407 else 7408 { 7409 semsg(_(e_invact2), actstr); 7410 return; 7411 } 7412 } 7413 else 7414 { 7415 emsg(_(e_stringreq)); 7416 return; 7417 } 7418 7419 if (set_tagstack(wp, d, action) == OK) 7420 rettv->vval.v_number = 0; 7421 } 7422 7423 #ifdef FEAT_CRYPT 7424 /* 7425 * "sha256({string})" function 7426 */ 7427 static void 7428 f_sha256(typval_T *argvars, typval_T *rettv) 7429 { 7430 char_u *p; 7431 7432 p = tv_get_string(&argvars[0]); 7433 rettv->vval.v_string = vim_strsave( 7434 sha256_bytes(p, (int)STRLEN(p), NULL, 0)); 7435 rettv->v_type = VAR_STRING; 7436 } 7437 #endif // FEAT_CRYPT 7438 7439 /* 7440 * "shellescape({string})" function 7441 */ 7442 static void 7443 f_shellescape(typval_T *argvars, typval_T *rettv) 7444 { 7445 int do_special = non_zero_arg(&argvars[1]); 7446 7447 rettv->vval.v_string = vim_strsave_shellescape( 7448 tv_get_string(&argvars[0]), do_special, do_special); 7449 rettv->v_type = VAR_STRING; 7450 } 7451 7452 /* 7453 * shiftwidth() function 7454 */ 7455 static void 7456 f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv) 7457 { 7458 rettv->vval.v_number = 0; 7459 7460 if (argvars[0].v_type != VAR_UNKNOWN) 7461 { 7462 long col; 7463 7464 col = (long)tv_get_number_chk(argvars, NULL); 7465 if (col < 0) 7466 return; // type error; errmsg already given 7467 #ifdef FEAT_VARTABS 7468 rettv->vval.v_number = get_sw_value_col(curbuf, col); 7469 return; 7470 #endif 7471 } 7472 7473 rettv->vval.v_number = get_sw_value(curbuf); 7474 } 7475 7476 #ifdef FEAT_FLOAT 7477 /* 7478 * "sin()" function 7479 */ 7480 static void 7481 f_sin(typval_T *argvars, typval_T *rettv) 7482 { 7483 float_T f = 0.0; 7484 7485 rettv->v_type = VAR_FLOAT; 7486 if (get_float_arg(argvars, &f) == OK) 7487 rettv->vval.v_float = sin(f); 7488 else 7489 rettv->vval.v_float = 0.0; 7490 } 7491 7492 /* 7493 * "sinh()" function 7494 */ 7495 static void 7496 f_sinh(typval_T *argvars, typval_T *rettv) 7497 { 7498 float_T f = 0.0; 7499 7500 rettv->v_type = VAR_FLOAT; 7501 if (get_float_arg(argvars, &f) == OK) 7502 rettv->vval.v_float = sinh(f); 7503 else 7504 rettv->vval.v_float = 0.0; 7505 } 7506 #endif 7507 7508 /* 7509 * "soundfold({word})" function 7510 */ 7511 static void 7512 f_soundfold(typval_T *argvars, typval_T *rettv) 7513 { 7514 char_u *s; 7515 7516 rettv->v_type = VAR_STRING; 7517 s = tv_get_string(&argvars[0]); 7518 #ifdef FEAT_SPELL 7519 rettv->vval.v_string = eval_soundfold(s); 7520 #else 7521 rettv->vval.v_string = vim_strsave(s); 7522 #endif 7523 } 7524 7525 /* 7526 * "spellbadword()" function 7527 */ 7528 static void 7529 f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv) 7530 { 7531 char_u *word = (char_u *)""; 7532 hlf_T attr = HLF_COUNT; 7533 int len = 0; 7534 7535 if (rettv_list_alloc(rettv) == FAIL) 7536 return; 7537 7538 #ifdef FEAT_SPELL 7539 if (argvars[0].v_type == VAR_UNKNOWN) 7540 { 7541 // Find the start and length of the badly spelled word. 7542 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr); 7543 if (len != 0) 7544 { 7545 word = ml_get_cursor(); 7546 curwin->w_set_curswant = TRUE; 7547 } 7548 } 7549 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL) 7550 { 7551 char_u *str = tv_get_string_chk(&argvars[0]); 7552 int capcol = -1; 7553 7554 if (str != NULL) 7555 { 7556 // Check the argument for spelling. 7557 while (*str != NUL) 7558 { 7559 len = spell_check(curwin, str, &attr, &capcol, FALSE); 7560 if (attr != HLF_COUNT) 7561 { 7562 word = str; 7563 break; 7564 } 7565 str += len; 7566 capcol -= len; 7567 len = 0; 7568 } 7569 } 7570 } 7571 #endif 7572 7573 list_append_string(rettv->vval.v_list, word, len); 7574 list_append_string(rettv->vval.v_list, (char_u *)( 7575 attr == HLF_SPB ? "bad" : 7576 attr == HLF_SPR ? "rare" : 7577 attr == HLF_SPL ? "local" : 7578 attr == HLF_SPC ? "caps" : 7579 ""), -1); 7580 } 7581 7582 /* 7583 * "spellsuggest()" function 7584 */ 7585 static void 7586 f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv) 7587 { 7588 #ifdef FEAT_SPELL 7589 char_u *str; 7590 int typeerr = FALSE; 7591 int maxcount; 7592 garray_T ga; 7593 int i; 7594 listitem_T *li; 7595 int need_capital = FALSE; 7596 #endif 7597 7598 if (rettv_list_alloc(rettv) == FAIL) 7599 return; 7600 7601 #ifdef FEAT_SPELL 7602 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) 7603 { 7604 str = tv_get_string(&argvars[0]); 7605 if (argvars[1].v_type != VAR_UNKNOWN) 7606 { 7607 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr); 7608 if (maxcount <= 0) 7609 return; 7610 if (argvars[2].v_type != VAR_UNKNOWN) 7611 { 7612 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr); 7613 if (typeerr) 7614 return; 7615 } 7616 } 7617 else 7618 maxcount = 25; 7619 7620 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE); 7621 7622 for (i = 0; i < ga.ga_len; ++i) 7623 { 7624 str = ((char_u **)ga.ga_data)[i]; 7625 7626 li = listitem_alloc(); 7627 if (li == NULL) 7628 vim_free(str); 7629 else 7630 { 7631 li->li_tv.v_type = VAR_STRING; 7632 li->li_tv.v_lock = 0; 7633 li->li_tv.vval.v_string = str; 7634 list_append(rettv->vval.v_list, li); 7635 } 7636 } 7637 ga_clear(&ga); 7638 } 7639 #endif 7640 } 7641 7642 static void 7643 f_split(typval_T *argvars, typval_T *rettv) 7644 { 7645 char_u *str; 7646 char_u *end; 7647 char_u *pat = NULL; 7648 regmatch_T regmatch; 7649 char_u patbuf[NUMBUFLEN]; 7650 char_u *save_cpo; 7651 int match; 7652 colnr_T col = 0; 7653 int keepempty = FALSE; 7654 int typeerr = FALSE; 7655 7656 // Make 'cpoptions' empty, the 'l' flag should not be used here. 7657 save_cpo = p_cpo; 7658 p_cpo = (char_u *)""; 7659 7660 str = tv_get_string(&argvars[0]); 7661 if (argvars[1].v_type != VAR_UNKNOWN) 7662 { 7663 pat = tv_get_string_buf_chk(&argvars[1], patbuf); 7664 if (pat == NULL) 7665 typeerr = TRUE; 7666 if (argvars[2].v_type != VAR_UNKNOWN) 7667 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr); 7668 } 7669 if (pat == NULL || *pat == NUL) 7670 pat = (char_u *)"[\\x01- ]\\+"; 7671 7672 if (rettv_list_alloc(rettv) == FAIL) 7673 return; 7674 if (typeerr) 7675 return; 7676 7677 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); 7678 if (regmatch.regprog != NULL) 7679 { 7680 regmatch.rm_ic = FALSE; 7681 while (*str != NUL || keepempty) 7682 { 7683 if (*str == NUL) 7684 match = FALSE; // empty item at the end 7685 else 7686 match = vim_regexec_nl(®match, str, col); 7687 if (match) 7688 end = regmatch.startp[0]; 7689 else 7690 end = str + STRLEN(str); 7691 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0 7692 && *str != NUL && match && end < regmatch.endp[0])) 7693 { 7694 if (list_append_string(rettv->vval.v_list, str, 7695 (int)(end - str)) == FAIL) 7696 break; 7697 } 7698 if (!match) 7699 break; 7700 // Advance to just after the match. 7701 if (regmatch.endp[0] > str) 7702 col = 0; 7703 else 7704 // Don't get stuck at the same match. 7705 col = (*mb_ptr2len)(regmatch.endp[0]); 7706 str = regmatch.endp[0]; 7707 } 7708 7709 vim_regfree(regmatch.regprog); 7710 } 7711 7712 p_cpo = save_cpo; 7713 } 7714 7715 #ifdef FEAT_FLOAT 7716 /* 7717 * "sqrt()" function 7718 */ 7719 static void 7720 f_sqrt(typval_T *argvars, typval_T *rettv) 7721 { 7722 float_T f = 0.0; 7723 7724 rettv->v_type = VAR_FLOAT; 7725 if (get_float_arg(argvars, &f) == OK) 7726 rettv->vval.v_float = sqrt(f); 7727 else 7728 rettv->vval.v_float = 0.0; 7729 } 7730 #endif 7731 7732 #ifdef FEAT_FLOAT 7733 /* 7734 * "str2float()" function 7735 */ 7736 static void 7737 f_str2float(typval_T *argvars, typval_T *rettv) 7738 { 7739 char_u *p = skipwhite(tv_get_string(&argvars[0])); 7740 int isneg = (*p == '-'); 7741 7742 if (*p == '+' || *p == '-') 7743 p = skipwhite(p + 1); 7744 (void)string2float(p, &rettv->vval.v_float); 7745 if (isneg) 7746 rettv->vval.v_float *= -1; 7747 rettv->v_type = VAR_FLOAT; 7748 } 7749 #endif 7750 7751 /* 7752 * "str2list()" function 7753 */ 7754 static void 7755 f_str2list(typval_T *argvars, typval_T *rettv) 7756 { 7757 char_u *p; 7758 int utf8 = FALSE; 7759 7760 if (rettv_list_alloc(rettv) == FAIL) 7761 return; 7762 7763 if (argvars[1].v_type != VAR_UNKNOWN) 7764 utf8 = (int)tv_get_number_chk(&argvars[1], NULL); 7765 7766 p = tv_get_string(&argvars[0]); 7767 7768 if (has_mbyte || utf8) 7769 { 7770 int (*ptr2len)(char_u *); 7771 int (*ptr2char)(char_u *); 7772 7773 if (utf8 || enc_utf8) 7774 { 7775 ptr2len = utf_ptr2len; 7776 ptr2char = utf_ptr2char; 7777 } 7778 else 7779 { 7780 ptr2len = mb_ptr2len; 7781 ptr2char = mb_ptr2char; 7782 } 7783 7784 for ( ; *p != NUL; p += (*ptr2len)(p)) 7785 list_append_number(rettv->vval.v_list, (*ptr2char)(p)); 7786 } 7787 else 7788 for ( ; *p != NUL; ++p) 7789 list_append_number(rettv->vval.v_list, *p); 7790 } 7791 7792 /* 7793 * "str2nr()" function 7794 */ 7795 static void 7796 f_str2nr(typval_T *argvars, typval_T *rettv) 7797 { 7798 int base = 10; 7799 char_u *p; 7800 varnumber_T n; 7801 int what = 0; 7802 int isneg; 7803 7804 if (argvars[1].v_type != VAR_UNKNOWN) 7805 { 7806 base = (int)tv_get_number(&argvars[1]); 7807 if (base != 2 && base != 8 && base != 10 && base != 16) 7808 { 7809 emsg(_(e_invarg)); 7810 return; 7811 } 7812 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2])) 7813 what |= STR2NR_QUOTE; 7814 } 7815 7816 p = skipwhite(tv_get_string(&argvars[0])); 7817 isneg = (*p == '-'); 7818 if (*p == '+' || *p == '-') 7819 p = skipwhite(p + 1); 7820 switch (base) 7821 { 7822 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break; 7823 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break; 7824 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break; 7825 } 7826 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE); 7827 // Text after the number is silently ignored. 7828 if (isneg) 7829 rettv->vval.v_number = -n; 7830 else 7831 rettv->vval.v_number = n; 7832 7833 } 7834 7835 /* 7836 * "strgetchar()" function 7837 */ 7838 static void 7839 f_strgetchar(typval_T *argvars, typval_T *rettv) 7840 { 7841 char_u *str; 7842 int len; 7843 int error = FALSE; 7844 int charidx; 7845 int byteidx = 0; 7846 7847 rettv->vval.v_number = -1; 7848 str = tv_get_string_chk(&argvars[0]); 7849 if (str == NULL) 7850 return; 7851 len = (int)STRLEN(str); 7852 charidx = (int)tv_get_number_chk(&argvars[1], &error); 7853 if (error) 7854 return; 7855 7856 while (charidx >= 0 && byteidx < len) 7857 { 7858 if (charidx == 0) 7859 { 7860 rettv->vval.v_number = mb_ptr2char(str + byteidx); 7861 break; 7862 } 7863 --charidx; 7864 byteidx += MB_CPTR2LEN(str + byteidx); 7865 } 7866 } 7867 7868 /* 7869 * "stridx()" function 7870 */ 7871 static void 7872 f_stridx(typval_T *argvars, typval_T *rettv) 7873 { 7874 char_u buf[NUMBUFLEN]; 7875 char_u *needle; 7876 char_u *haystack; 7877 char_u *save_haystack; 7878 char_u *pos; 7879 int start_idx; 7880 7881 needle = tv_get_string_chk(&argvars[1]); 7882 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf); 7883 rettv->vval.v_number = -1; 7884 if (needle == NULL || haystack == NULL) 7885 return; // type error; errmsg already given 7886 7887 if (argvars[2].v_type != VAR_UNKNOWN) 7888 { 7889 int error = FALSE; 7890 7891 start_idx = (int)tv_get_number_chk(&argvars[2], &error); 7892 if (error || start_idx >= (int)STRLEN(haystack)) 7893 return; 7894 if (start_idx >= 0) 7895 haystack += start_idx; 7896 } 7897 7898 pos = (char_u *)strstr((char *)haystack, (char *)needle); 7899 if (pos != NULL) 7900 rettv->vval.v_number = (varnumber_T)(pos - save_haystack); 7901 } 7902 7903 /* 7904 * "string()" function 7905 */ 7906 void 7907 f_string(typval_T *argvars, typval_T *rettv) 7908 { 7909 char_u *tofree; 7910 char_u numbuf[NUMBUFLEN]; 7911 7912 rettv->v_type = VAR_STRING; 7913 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf, 7914 get_copyID()); 7915 // Make a copy if we have a value but it's not in allocated memory. 7916 if (rettv->vval.v_string != NULL && tofree == NULL) 7917 rettv->vval.v_string = vim_strsave(rettv->vval.v_string); 7918 } 7919 7920 /* 7921 * "strlen()" function 7922 */ 7923 static void 7924 f_strlen(typval_T *argvars, typval_T *rettv) 7925 { 7926 rettv->vval.v_number = (varnumber_T)(STRLEN( 7927 tv_get_string(&argvars[0]))); 7928 } 7929 7930 /* 7931 * "strchars()" function 7932 */ 7933 static void 7934 f_strchars(typval_T *argvars, typval_T *rettv) 7935 { 7936 char_u *s = tv_get_string(&argvars[0]); 7937 int skipcc = 0; 7938 varnumber_T len = 0; 7939 int (*func_mb_ptr2char_adv)(char_u **pp); 7940 7941 if (argvars[1].v_type != VAR_UNKNOWN) 7942 skipcc = (int)tv_get_number_chk(&argvars[1], NULL); 7943 if (skipcc < 0 || skipcc > 1) 7944 emsg(_(e_invarg)); 7945 else 7946 { 7947 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv; 7948 while (*s != NUL) 7949 { 7950 func_mb_ptr2char_adv(&s); 7951 ++len; 7952 } 7953 rettv->vval.v_number = len; 7954 } 7955 } 7956 7957 /* 7958 * "strdisplaywidth()" function 7959 */ 7960 static void 7961 f_strdisplaywidth(typval_T *argvars, typval_T *rettv) 7962 { 7963 char_u *s = tv_get_string(&argvars[0]); 7964 int col = 0; 7965 7966 if (argvars[1].v_type != VAR_UNKNOWN) 7967 col = (int)tv_get_number(&argvars[1]); 7968 7969 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col); 7970 } 7971 7972 /* 7973 * "strwidth()" function 7974 */ 7975 static void 7976 f_strwidth(typval_T *argvars, typval_T *rettv) 7977 { 7978 char_u *s = tv_get_string(&argvars[0]); 7979 7980 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1)); 7981 } 7982 7983 /* 7984 * "strcharpart()" function 7985 */ 7986 static void 7987 f_strcharpart(typval_T *argvars, typval_T *rettv) 7988 { 7989 char_u *p; 7990 int nchar; 7991 int nbyte = 0; 7992 int charlen; 7993 int len = 0; 7994 int slen; 7995 int error = FALSE; 7996 7997 p = tv_get_string(&argvars[0]); 7998 slen = (int)STRLEN(p); 7999 8000 nchar = (int)tv_get_number_chk(&argvars[1], &error); 8001 if (!error) 8002 { 8003 if (nchar > 0) 8004 while (nchar > 0 && nbyte < slen) 8005 { 8006 nbyte += MB_CPTR2LEN(p + nbyte); 8007 --nchar; 8008 } 8009 else 8010 nbyte = nchar; 8011 if (argvars[2].v_type != VAR_UNKNOWN) 8012 { 8013 charlen = (int)tv_get_number(&argvars[2]); 8014 while (charlen > 0 && nbyte + len < slen) 8015 { 8016 int off = nbyte + len; 8017 8018 if (off < 0) 8019 len += 1; 8020 else 8021 len += MB_CPTR2LEN(p + off); 8022 --charlen; 8023 } 8024 } 8025 else 8026 len = slen - nbyte; // default: all bytes that are available. 8027 } 8028 8029 /* 8030 * Only return the overlap between the specified part and the actual 8031 * string. 8032 */ 8033 if (nbyte < 0) 8034 { 8035 len += nbyte; 8036 nbyte = 0; 8037 } 8038 else if (nbyte > slen) 8039 nbyte = slen; 8040 if (len < 0) 8041 len = 0; 8042 else if (nbyte + len > slen) 8043 len = slen - nbyte; 8044 8045 rettv->v_type = VAR_STRING; 8046 rettv->vval.v_string = vim_strnsave(p + nbyte, len); 8047 } 8048 8049 /* 8050 * "strpart()" function 8051 */ 8052 static void 8053 f_strpart(typval_T *argvars, typval_T *rettv) 8054 { 8055 char_u *p; 8056 int n; 8057 int len; 8058 int slen; 8059 int error = FALSE; 8060 8061 p = tv_get_string(&argvars[0]); 8062 slen = (int)STRLEN(p); 8063 8064 n = (int)tv_get_number_chk(&argvars[1], &error); 8065 if (error) 8066 len = 0; 8067 else if (argvars[2].v_type != VAR_UNKNOWN) 8068 len = (int)tv_get_number(&argvars[2]); 8069 else 8070 len = slen - n; // default len: all bytes that are available. 8071 8072 /* 8073 * Only return the overlap between the specified part and the actual 8074 * string. 8075 */ 8076 if (n < 0) 8077 { 8078 len += n; 8079 n = 0; 8080 } 8081 else if (n > slen) 8082 n = slen; 8083 if (len < 0) 8084 len = 0; 8085 else if (n + len > slen) 8086 len = slen - n; 8087 8088 rettv->v_type = VAR_STRING; 8089 rettv->vval.v_string = vim_strnsave(p + n, len); 8090 } 8091 8092 /* 8093 * "strridx()" function 8094 */ 8095 static void 8096 f_strridx(typval_T *argvars, typval_T *rettv) 8097 { 8098 char_u buf[NUMBUFLEN]; 8099 char_u *needle; 8100 char_u *haystack; 8101 char_u *rest; 8102 char_u *lastmatch = NULL; 8103 int haystack_len, end_idx; 8104 8105 needle = tv_get_string_chk(&argvars[1]); 8106 haystack = tv_get_string_buf_chk(&argvars[0], buf); 8107 8108 rettv->vval.v_number = -1; 8109 if (needle == NULL || haystack == NULL) 8110 return; // type error; errmsg already given 8111 8112 haystack_len = (int)STRLEN(haystack); 8113 if (argvars[2].v_type != VAR_UNKNOWN) 8114 { 8115 // Third argument: upper limit for index 8116 end_idx = (int)tv_get_number_chk(&argvars[2], NULL); 8117 if (end_idx < 0) 8118 return; // can never find a match 8119 } 8120 else 8121 end_idx = haystack_len; 8122 8123 if (*needle == NUL) 8124 { 8125 // Empty string matches past the end. 8126 lastmatch = haystack + end_idx; 8127 } 8128 else 8129 { 8130 for (rest = haystack; *rest != '\0'; ++rest) 8131 { 8132 rest = (char_u *)strstr((char *)rest, (char *)needle); 8133 if (rest == NULL || rest > haystack + end_idx) 8134 break; 8135 lastmatch = rest; 8136 } 8137 } 8138 8139 if (lastmatch == NULL) 8140 rettv->vval.v_number = -1; 8141 else 8142 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack); 8143 } 8144 8145 /* 8146 * "strtrans()" function 8147 */ 8148 static void 8149 f_strtrans(typval_T *argvars, typval_T *rettv) 8150 { 8151 rettv->v_type = VAR_STRING; 8152 rettv->vval.v_string = transstr(tv_get_string(&argvars[0])); 8153 } 8154 8155 /* 8156 * "submatch()" function 8157 */ 8158 static void 8159 f_submatch(typval_T *argvars, typval_T *rettv) 8160 { 8161 int error = FALSE; 8162 int no; 8163 int retList = 0; 8164 8165 no = (int)tv_get_number_chk(&argvars[0], &error); 8166 if (error) 8167 return; 8168 if (no < 0 || no >= NSUBEXP) 8169 { 8170 semsg(_("E935: invalid submatch number: %d"), no); 8171 return; 8172 } 8173 if (argvars[1].v_type != VAR_UNKNOWN) 8174 retList = (int)tv_get_number_chk(&argvars[1], &error); 8175 if (error) 8176 return; 8177 8178 if (retList == 0) 8179 { 8180 rettv->v_type = VAR_STRING; 8181 rettv->vval.v_string = reg_submatch(no); 8182 } 8183 else 8184 { 8185 rettv->v_type = VAR_LIST; 8186 rettv->vval.v_list = reg_submatch_list(no); 8187 } 8188 } 8189 8190 /* 8191 * "substitute()" function 8192 */ 8193 static void 8194 f_substitute(typval_T *argvars, typval_T *rettv) 8195 { 8196 char_u patbuf[NUMBUFLEN]; 8197 char_u subbuf[NUMBUFLEN]; 8198 char_u flagsbuf[NUMBUFLEN]; 8199 8200 char_u *str = tv_get_string_chk(&argvars[0]); 8201 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf); 8202 char_u *sub = NULL; 8203 typval_T *expr = NULL; 8204 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf); 8205 8206 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL) 8207 expr = &argvars[2]; 8208 else 8209 sub = tv_get_string_buf_chk(&argvars[2], subbuf); 8210 8211 rettv->v_type = VAR_STRING; 8212 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL) 8213 || flg == NULL) 8214 rettv->vval.v_string = NULL; 8215 else 8216 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg); 8217 } 8218 8219 /* 8220 * "swapinfo(swap_filename)" function 8221 */ 8222 static void 8223 f_swapinfo(typval_T *argvars, typval_T *rettv) 8224 { 8225 if (rettv_dict_alloc(rettv) == OK) 8226 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict); 8227 } 8228 8229 /* 8230 * "swapname(expr)" function 8231 */ 8232 static void 8233 f_swapname(typval_T *argvars, typval_T *rettv) 8234 { 8235 buf_T *buf; 8236 8237 rettv->v_type = VAR_STRING; 8238 buf = tv_get_buf(&argvars[0], FALSE); 8239 if (buf == NULL || buf->b_ml.ml_mfp == NULL 8240 || buf->b_ml.ml_mfp->mf_fname == NULL) 8241 rettv->vval.v_string = NULL; 8242 else 8243 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname); 8244 } 8245 8246 /* 8247 * "synID(lnum, col, trans)" function 8248 */ 8249 static void 8250 f_synID(typval_T *argvars UNUSED, typval_T *rettv) 8251 { 8252 int id = 0; 8253 #ifdef FEAT_SYN_HL 8254 linenr_T lnum; 8255 colnr_T col; 8256 int trans; 8257 int transerr = FALSE; 8258 8259 lnum = tv_get_lnum(argvars); // -1 on type error 8260 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error 8261 trans = (int)tv_get_number_chk(&argvars[2], &transerr); 8262 8263 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count 8264 && col >= 0 && col < (long)STRLEN(ml_get(lnum))) 8265 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE); 8266 #endif 8267 8268 rettv->vval.v_number = id; 8269 } 8270 8271 /* 8272 * "synIDattr(id, what [, mode])" function 8273 */ 8274 static void 8275 f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv) 8276 { 8277 char_u *p = NULL; 8278 #ifdef FEAT_SYN_HL 8279 int id; 8280 char_u *what; 8281 char_u *mode; 8282 char_u modebuf[NUMBUFLEN]; 8283 int modec; 8284 8285 id = (int)tv_get_number(&argvars[0]); 8286 what = tv_get_string(&argvars[1]); 8287 if (argvars[2].v_type != VAR_UNKNOWN) 8288 { 8289 mode = tv_get_string_buf(&argvars[2], modebuf); 8290 modec = TOLOWER_ASC(mode[0]); 8291 if (modec != 't' && modec != 'c' && modec != 'g') 8292 modec = 0; // replace invalid with current 8293 } 8294 else 8295 { 8296 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 8297 if (USE_24BIT) 8298 modec = 'g'; 8299 else 8300 #endif 8301 if (t_colors > 1) 8302 modec = 'c'; 8303 else 8304 modec = 't'; 8305 } 8306 8307 switch (TOLOWER_ASC(what[0])) 8308 { 8309 case 'b': 8310 if (TOLOWER_ASC(what[1]) == 'g') // bg[#] 8311 p = highlight_color(id, what, modec); 8312 else // bold 8313 p = highlight_has_attr(id, HL_BOLD, modec); 8314 break; 8315 8316 case 'f': // fg[#] or font 8317 p = highlight_color(id, what, modec); 8318 break; 8319 8320 case 'i': 8321 if (TOLOWER_ASC(what[1]) == 'n') // inverse 8322 p = highlight_has_attr(id, HL_INVERSE, modec); 8323 else // italic 8324 p = highlight_has_attr(id, HL_ITALIC, modec); 8325 break; 8326 8327 case 'n': // name 8328 p = get_highlight_name_ext(NULL, id - 1, FALSE); 8329 break; 8330 8331 case 'r': // reverse 8332 p = highlight_has_attr(id, HL_INVERSE, modec); 8333 break; 8334 8335 case 's': 8336 if (TOLOWER_ASC(what[1]) == 'p') // sp[#] 8337 p = highlight_color(id, what, modec); 8338 // strikeout 8339 else if (TOLOWER_ASC(what[1]) == 't' && 8340 TOLOWER_ASC(what[2]) == 'r') 8341 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec); 8342 else // standout 8343 p = highlight_has_attr(id, HL_STANDOUT, modec); 8344 break; 8345 8346 case 'u': 8347 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c') 8348 // underline 8349 p = highlight_has_attr(id, HL_UNDERLINE, modec); 8350 else 8351 // undercurl 8352 p = highlight_has_attr(id, HL_UNDERCURL, modec); 8353 break; 8354 } 8355 8356 if (p != NULL) 8357 p = vim_strsave(p); 8358 #endif 8359 rettv->v_type = VAR_STRING; 8360 rettv->vval.v_string = p; 8361 } 8362 8363 /* 8364 * "synIDtrans(id)" function 8365 */ 8366 static void 8367 f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv) 8368 { 8369 int id; 8370 8371 #ifdef FEAT_SYN_HL 8372 id = (int)tv_get_number(&argvars[0]); 8373 8374 if (id > 0) 8375 id = syn_get_final_id(id); 8376 else 8377 #endif 8378 id = 0; 8379 8380 rettv->vval.v_number = id; 8381 } 8382 8383 /* 8384 * "synconcealed(lnum, col)" function 8385 */ 8386 static void 8387 f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv) 8388 { 8389 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) 8390 linenr_T lnum; 8391 colnr_T col; 8392 int syntax_flags = 0; 8393 int cchar; 8394 int matchid = 0; 8395 char_u str[NUMBUFLEN]; 8396 #endif 8397 8398 rettv_list_set(rettv, NULL); 8399 8400 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) 8401 lnum = tv_get_lnum(argvars); // -1 on type error 8402 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error 8403 8404 CLEAR_FIELD(str); 8405 8406 if (rettv_list_alloc(rettv) != FAIL) 8407 { 8408 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count 8409 && col >= 0 && col <= (long)STRLEN(ml_get(lnum)) 8410 && curwin->w_p_cole > 0) 8411 { 8412 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE); 8413 syntax_flags = get_syntax_info(&matchid); 8414 8415 // get the conceal character 8416 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3) 8417 { 8418 cchar = syn_get_sub_char(); 8419 if (cchar == NUL && curwin->w_p_cole == 1) 8420 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal; 8421 if (cchar != NUL) 8422 { 8423 if (has_mbyte) 8424 (*mb_char2bytes)(cchar, str); 8425 else 8426 str[0] = cchar; 8427 } 8428 } 8429 } 8430 8431 list_append_number(rettv->vval.v_list, 8432 (syntax_flags & HL_CONCEAL) != 0); 8433 // -1 to auto-determine strlen 8434 list_append_string(rettv->vval.v_list, str, -1); 8435 list_append_number(rettv->vval.v_list, matchid); 8436 } 8437 #endif 8438 } 8439 8440 /* 8441 * "synstack(lnum, col)" function 8442 */ 8443 static void 8444 f_synstack(typval_T *argvars UNUSED, typval_T *rettv) 8445 { 8446 #ifdef FEAT_SYN_HL 8447 linenr_T lnum; 8448 colnr_T col; 8449 int i; 8450 int id; 8451 #endif 8452 8453 rettv_list_set(rettv, NULL); 8454 8455 #ifdef FEAT_SYN_HL 8456 lnum = tv_get_lnum(argvars); // -1 on type error 8457 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error 8458 8459 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count 8460 && col >= 0 && col <= (long)STRLEN(ml_get(lnum)) 8461 && rettv_list_alloc(rettv) != FAIL) 8462 { 8463 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE); 8464 for (i = 0; ; ++i) 8465 { 8466 id = syn_get_stack_item(i); 8467 if (id < 0) 8468 break; 8469 if (list_append_number(rettv->vval.v_list, id) == FAIL) 8470 break; 8471 } 8472 } 8473 #endif 8474 } 8475 8476 /* 8477 * "tabpagebuflist()" function 8478 */ 8479 static void 8480 f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 8481 { 8482 tabpage_T *tp; 8483 win_T *wp = NULL; 8484 8485 if (argvars[0].v_type == VAR_UNKNOWN) 8486 wp = firstwin; 8487 else 8488 { 8489 tp = find_tabpage((int)tv_get_number(&argvars[0])); 8490 if (tp != NULL) 8491 wp = (tp == curtab) ? firstwin : tp->tp_firstwin; 8492 } 8493 if (wp != NULL && rettv_list_alloc(rettv) != FAIL) 8494 { 8495 for (; wp != NULL; wp = wp->w_next) 8496 if (list_append_number(rettv->vval.v_list, 8497 wp->w_buffer->b_fnum) == FAIL) 8498 break; 8499 } 8500 } 8501 8502 /* 8503 * "tagfiles()" function 8504 */ 8505 static void 8506 f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv) 8507 { 8508 char_u *fname; 8509 tagname_T tn; 8510 int first; 8511 8512 if (rettv_list_alloc(rettv) == FAIL) 8513 return; 8514 fname = alloc(MAXPATHL); 8515 if (fname == NULL) 8516 return; 8517 8518 for (first = TRUE; ; first = FALSE) 8519 if (get_tagfname(&tn, first, fname) == FAIL 8520 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL) 8521 break; 8522 tagname_free(&tn); 8523 vim_free(fname); 8524 } 8525 8526 /* 8527 * "taglist()" function 8528 */ 8529 static void 8530 f_taglist(typval_T *argvars, typval_T *rettv) 8531 { 8532 char_u *fname = NULL; 8533 char_u *tag_pattern; 8534 8535 tag_pattern = tv_get_string(&argvars[0]); 8536 8537 rettv->vval.v_number = FALSE; 8538 if (*tag_pattern == NUL) 8539 return; 8540 8541 if (argvars[1].v_type != VAR_UNKNOWN) 8542 fname = tv_get_string(&argvars[1]); 8543 if (rettv_list_alloc(rettv) == OK) 8544 (void)get_tags(rettv->vval.v_list, tag_pattern, fname); 8545 } 8546 8547 #ifdef FEAT_FLOAT 8548 /* 8549 * "tan()" function 8550 */ 8551 static void 8552 f_tan(typval_T *argvars, typval_T *rettv) 8553 { 8554 float_T f = 0.0; 8555 8556 rettv->v_type = VAR_FLOAT; 8557 if (get_float_arg(argvars, &f) == OK) 8558 rettv->vval.v_float = tan(f); 8559 else 8560 rettv->vval.v_float = 0.0; 8561 } 8562 8563 /* 8564 * "tanh()" function 8565 */ 8566 static void 8567 f_tanh(typval_T *argvars, typval_T *rettv) 8568 { 8569 float_T f = 0.0; 8570 8571 rettv->v_type = VAR_FLOAT; 8572 if (get_float_arg(argvars, &f) == OK) 8573 rettv->vval.v_float = tanh(f); 8574 else 8575 rettv->vval.v_float = 0.0; 8576 } 8577 #endif 8578 8579 /* 8580 * "tolower(string)" function 8581 */ 8582 static void 8583 f_tolower(typval_T *argvars, typval_T *rettv) 8584 { 8585 rettv->v_type = VAR_STRING; 8586 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0])); 8587 } 8588 8589 /* 8590 * "toupper(string)" function 8591 */ 8592 static void 8593 f_toupper(typval_T *argvars, typval_T *rettv) 8594 { 8595 rettv->v_type = VAR_STRING; 8596 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0])); 8597 } 8598 8599 /* 8600 * "tr(string, fromstr, tostr)" function 8601 */ 8602 static void 8603 f_tr(typval_T *argvars, typval_T *rettv) 8604 { 8605 char_u *in_str; 8606 char_u *fromstr; 8607 char_u *tostr; 8608 char_u *p; 8609 int inlen; 8610 int fromlen; 8611 int tolen; 8612 int idx; 8613 char_u *cpstr; 8614 int cplen; 8615 int first = TRUE; 8616 char_u buf[NUMBUFLEN]; 8617 char_u buf2[NUMBUFLEN]; 8618 garray_T ga; 8619 8620 in_str = tv_get_string(&argvars[0]); 8621 fromstr = tv_get_string_buf_chk(&argvars[1], buf); 8622 tostr = tv_get_string_buf_chk(&argvars[2], buf2); 8623 8624 // Default return value: empty string. 8625 rettv->v_type = VAR_STRING; 8626 rettv->vval.v_string = NULL; 8627 if (fromstr == NULL || tostr == NULL) 8628 return; // type error; errmsg already given 8629 ga_init2(&ga, (int)sizeof(char), 80); 8630 8631 if (!has_mbyte) 8632 // not multi-byte: fromstr and tostr must be the same length 8633 if (STRLEN(fromstr) != STRLEN(tostr)) 8634 { 8635 error: 8636 semsg(_(e_invarg2), fromstr); 8637 ga_clear(&ga); 8638 return; 8639 } 8640 8641 // fromstr and tostr have to contain the same number of chars 8642 while (*in_str != NUL) 8643 { 8644 if (has_mbyte) 8645 { 8646 inlen = (*mb_ptr2len)(in_str); 8647 cpstr = in_str; 8648 cplen = inlen; 8649 idx = 0; 8650 for (p = fromstr; *p != NUL; p += fromlen) 8651 { 8652 fromlen = (*mb_ptr2len)(p); 8653 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0) 8654 { 8655 for (p = tostr; *p != NUL; p += tolen) 8656 { 8657 tolen = (*mb_ptr2len)(p); 8658 if (idx-- == 0) 8659 { 8660 cplen = tolen; 8661 cpstr = p; 8662 break; 8663 } 8664 } 8665 if (*p == NUL) // tostr is shorter than fromstr 8666 goto error; 8667 break; 8668 } 8669 ++idx; 8670 } 8671 8672 if (first && cpstr == in_str) 8673 { 8674 // Check that fromstr and tostr have the same number of 8675 // (multi-byte) characters. Done only once when a character 8676 // of in_str doesn't appear in fromstr. 8677 first = FALSE; 8678 for (p = tostr; *p != NUL; p += tolen) 8679 { 8680 tolen = (*mb_ptr2len)(p); 8681 --idx; 8682 } 8683 if (idx != 0) 8684 goto error; 8685 } 8686 8687 (void)ga_grow(&ga, cplen); 8688 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen); 8689 ga.ga_len += cplen; 8690 8691 in_str += inlen; 8692 } 8693 else 8694 { 8695 // When not using multi-byte chars we can do it faster. 8696 p = vim_strchr(fromstr, *in_str); 8697 if (p != NULL) 8698 ga_append(&ga, tostr[p - fromstr]); 8699 else 8700 ga_append(&ga, *in_str); 8701 ++in_str; 8702 } 8703 } 8704 8705 // add a terminating NUL 8706 (void)ga_grow(&ga, 1); 8707 ga_append(&ga, NUL); 8708 8709 rettv->vval.v_string = ga.ga_data; 8710 } 8711 8712 /* 8713 * "trim({expr})" function 8714 */ 8715 static void 8716 f_trim(typval_T *argvars, typval_T *rettv) 8717 { 8718 char_u buf1[NUMBUFLEN]; 8719 char_u buf2[NUMBUFLEN]; 8720 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1); 8721 char_u *mask = NULL; 8722 char_u *tail; 8723 char_u *prev; 8724 char_u *p; 8725 int c1; 8726 8727 rettv->v_type = VAR_STRING; 8728 if (head == NULL) 8729 { 8730 rettv->vval.v_string = NULL; 8731 return; 8732 } 8733 8734 if (argvars[1].v_type == VAR_STRING) 8735 mask = tv_get_string_buf_chk(&argvars[1], buf2); 8736 8737 while (*head != NUL) 8738 { 8739 c1 = PTR2CHAR(head); 8740 if (mask == NULL) 8741 { 8742 if (c1 > ' ' && c1 != 0xa0) 8743 break; 8744 } 8745 else 8746 { 8747 for (p = mask; *p != NUL; MB_PTR_ADV(p)) 8748 if (c1 == PTR2CHAR(p)) 8749 break; 8750 if (*p == NUL) 8751 break; 8752 } 8753 MB_PTR_ADV(head); 8754 } 8755 8756 for (tail = head + STRLEN(head); tail > head; tail = prev) 8757 { 8758 prev = tail; 8759 MB_PTR_BACK(head, prev); 8760 c1 = PTR2CHAR(prev); 8761 if (mask == NULL) 8762 { 8763 if (c1 > ' ' && c1 != 0xa0) 8764 break; 8765 } 8766 else 8767 { 8768 for (p = mask; *p != NUL; MB_PTR_ADV(p)) 8769 if (c1 == PTR2CHAR(p)) 8770 break; 8771 if (*p == NUL) 8772 break; 8773 } 8774 } 8775 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head)); 8776 } 8777 8778 #ifdef FEAT_FLOAT 8779 /* 8780 * "trunc({float})" function 8781 */ 8782 static void 8783 f_trunc(typval_T *argvars, typval_T *rettv) 8784 { 8785 float_T f = 0.0; 8786 8787 rettv->v_type = VAR_FLOAT; 8788 if (get_float_arg(argvars, &f) == OK) 8789 // trunc() is not in C90, use floor() or ceil() instead. 8790 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f); 8791 else 8792 rettv->vval.v_float = 0.0; 8793 } 8794 #endif 8795 8796 /* 8797 * "type(expr)" function 8798 */ 8799 static void 8800 f_type(typval_T *argvars, typval_T *rettv) 8801 { 8802 int n = -1; 8803 8804 switch (argvars[0].v_type) 8805 { 8806 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break; 8807 case VAR_STRING: n = VAR_TYPE_STRING; break; 8808 case VAR_PARTIAL: 8809 case VAR_FUNC: n = VAR_TYPE_FUNC; break; 8810 case VAR_LIST: n = VAR_TYPE_LIST; break; 8811 case VAR_DICT: n = VAR_TYPE_DICT; break; 8812 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break; 8813 case VAR_BOOL: n = VAR_TYPE_BOOL; break; 8814 case VAR_SPECIAL: n = VAR_TYPE_NONE; break; 8815 case VAR_JOB: n = VAR_TYPE_JOB; break; 8816 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break; 8817 case VAR_BLOB: n = VAR_TYPE_BLOB; break; 8818 case VAR_UNKNOWN: 8819 case VAR_ANY: 8820 case VAR_VOID: 8821 internal_error_no_abort("f_type(UNKNOWN)"); 8822 n = -1; 8823 break; 8824 } 8825 rettv->vval.v_number = n; 8826 } 8827 8828 /* 8829 * "virtcol(string)" function 8830 */ 8831 static void 8832 f_virtcol(typval_T *argvars, typval_T *rettv) 8833 { 8834 colnr_T vcol = 0; 8835 pos_T *fp; 8836 int fnum = curbuf->b_fnum; 8837 int len; 8838 8839 fp = var2fpos(&argvars[0], FALSE, &fnum); 8840 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count 8841 && fnum == curbuf->b_fnum) 8842 { 8843 // Limit the column to a valid value, getvvcol() doesn't check. 8844 if (fp->col < 0) 8845 fp->col = 0; 8846 else 8847 { 8848 len = (int)STRLEN(ml_get(fp->lnum)); 8849 if (fp->col > len) 8850 fp->col = len; 8851 } 8852 getvvcol(curwin, fp, NULL, NULL, &vcol); 8853 ++vcol; 8854 } 8855 8856 rettv->vval.v_number = vcol; 8857 } 8858 8859 /* 8860 * "visualmode()" function 8861 */ 8862 static void 8863 f_visualmode(typval_T *argvars, typval_T *rettv) 8864 { 8865 char_u str[2]; 8866 8867 rettv->v_type = VAR_STRING; 8868 str[0] = curbuf->b_visual_mode_eval; 8869 str[1] = NUL; 8870 rettv->vval.v_string = vim_strsave(str); 8871 8872 // A non-zero number or non-empty string argument: reset mode. 8873 if (non_zero_arg(&argvars[0])) 8874 curbuf->b_visual_mode_eval = NUL; 8875 } 8876 8877 /* 8878 * "wildmenumode()" function 8879 */ 8880 static void 8881 f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 8882 { 8883 #ifdef FEAT_WILDMENU 8884 if (wild_menu_showing) 8885 rettv->vval.v_number = 1; 8886 #endif 8887 } 8888 8889 /* 8890 * "windowsversion()" function 8891 */ 8892 static void 8893 f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 8894 { 8895 rettv->v_type = VAR_STRING; 8896 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion); 8897 } 8898 8899 /* 8900 * "wordcount()" function 8901 */ 8902 static void 8903 f_wordcount(typval_T *argvars UNUSED, typval_T *rettv) 8904 { 8905 if (rettv_dict_alloc(rettv) == FAIL) 8906 return; 8907 cursor_pos_info(rettv->vval.v_dict); 8908 } 8909 8910 /* 8911 * "xor(expr, expr)" function 8912 */ 8913 static void 8914 f_xor(typval_T *argvars, typval_T *rettv) 8915 { 8916 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL) 8917 ^ tv_get_number_chk(&argvars[1], NULL); 8918 } 8919 8920 #endif // FEAT_EVAL 8921