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 AMIGA 20 # include <time.h> /* for strftime() */ 21 #endif 22 23 #ifdef VMS 24 # include <float.h> 25 #endif 26 27 #ifdef MACOS 28 # include <time.h> /* for time_t */ 29 #endif 30 31 static char *e_listarg = N_("E686: Argument of %s must be a List"); 32 #ifdef FEAT_QUICKFIX 33 static char *e_stringreq = N_("E928: String required"); 34 #endif 35 36 #ifdef FEAT_FLOAT 37 static void f_abs(typval_T *argvars, typval_T *rettv); 38 static void f_acos(typval_T *argvars, typval_T *rettv); 39 #endif 40 static void f_add(typval_T *argvars, typval_T *rettv); 41 static void f_and(typval_T *argvars, typval_T *rettv); 42 static void f_append(typval_T *argvars, typval_T *rettv); 43 static void f_argc(typval_T *argvars, typval_T *rettv); 44 static void f_argidx(typval_T *argvars, typval_T *rettv); 45 static void f_arglistid(typval_T *argvars, typval_T *rettv); 46 static void f_argv(typval_T *argvars, typval_T *rettv); 47 static void f_assert_equal(typval_T *argvars, typval_T *rettv); 48 static void f_assert_exception(typval_T *argvars, typval_T *rettv); 49 static void f_assert_fails(typval_T *argvars, typval_T *rettv); 50 static void f_assert_false(typval_T *argvars, typval_T *rettv); 51 static void f_assert_inrange(typval_T *argvars, typval_T *rettv); 52 static void f_assert_match(typval_T *argvars, typval_T *rettv); 53 static void f_assert_notequal(typval_T *argvars, typval_T *rettv); 54 static void f_assert_notmatch(typval_T *argvars, typval_T *rettv); 55 static void f_assert_report(typval_T *argvars, typval_T *rettv); 56 static void f_assert_true(typval_T *argvars, typval_T *rettv); 57 #ifdef FEAT_FLOAT 58 static void f_asin(typval_T *argvars, typval_T *rettv); 59 static void f_atan(typval_T *argvars, typval_T *rettv); 60 static void f_atan2(typval_T *argvars, typval_T *rettv); 61 #endif 62 #ifdef FEAT_BEVAL 63 static void f_balloon_show(typval_T *argvars, typval_T *rettv); 64 #endif 65 static void f_browse(typval_T *argvars, typval_T *rettv); 66 static void f_browsedir(typval_T *argvars, typval_T *rettv); 67 static void f_bufexists(typval_T *argvars, typval_T *rettv); 68 static void f_buflisted(typval_T *argvars, typval_T *rettv); 69 static void f_bufloaded(typval_T *argvars, typval_T *rettv); 70 static void f_bufname(typval_T *argvars, typval_T *rettv); 71 static void f_bufnr(typval_T *argvars, typval_T *rettv); 72 static void f_bufwinid(typval_T *argvars, typval_T *rettv); 73 static void f_bufwinnr(typval_T *argvars, typval_T *rettv); 74 static void f_byte2line(typval_T *argvars, typval_T *rettv); 75 static void byteidx(typval_T *argvars, typval_T *rettv, int comp); 76 static void f_byteidx(typval_T *argvars, typval_T *rettv); 77 static void f_byteidxcomp(typval_T *argvars, typval_T *rettv); 78 static void f_call(typval_T *argvars, typval_T *rettv); 79 #ifdef FEAT_FLOAT 80 static void f_ceil(typval_T *argvars, typval_T *rettv); 81 #endif 82 #ifdef FEAT_JOB_CHANNEL 83 static void f_ch_canread(typval_T *argvars, typval_T *rettv); 84 static void f_ch_close(typval_T *argvars, typval_T *rettv); 85 static void f_ch_close_in(typval_T *argvars, typval_T *rettv); 86 static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv); 87 static void f_ch_evalraw(typval_T *argvars, typval_T *rettv); 88 static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv); 89 static void f_ch_getjob(typval_T *argvars, typval_T *rettv); 90 static void f_ch_info(typval_T *argvars, typval_T *rettv); 91 static void f_ch_log(typval_T *argvars, typval_T *rettv); 92 static void f_ch_logfile(typval_T *argvars, typval_T *rettv); 93 static void f_ch_open(typval_T *argvars, typval_T *rettv); 94 static void f_ch_read(typval_T *argvars, typval_T *rettv); 95 static void f_ch_readraw(typval_T *argvars, typval_T *rettv); 96 static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv); 97 static void f_ch_sendraw(typval_T *argvars, typval_T *rettv); 98 static void f_ch_setoptions(typval_T *argvars, typval_T *rettv); 99 static void f_ch_status(typval_T *argvars, typval_T *rettv); 100 #endif 101 static void f_changenr(typval_T *argvars, typval_T *rettv); 102 static void f_char2nr(typval_T *argvars, typval_T *rettv); 103 static void f_cindent(typval_T *argvars, typval_T *rettv); 104 static void f_clearmatches(typval_T *argvars, typval_T *rettv); 105 static void f_col(typval_T *argvars, typval_T *rettv); 106 #if defined(FEAT_INS_EXPAND) 107 static void f_complete(typval_T *argvars, typval_T *rettv); 108 static void f_complete_add(typval_T *argvars, typval_T *rettv); 109 static void f_complete_check(typval_T *argvars, typval_T *rettv); 110 #endif 111 static void f_confirm(typval_T *argvars, typval_T *rettv); 112 static void f_copy(typval_T *argvars, typval_T *rettv); 113 #ifdef FEAT_FLOAT 114 static void f_cos(typval_T *argvars, typval_T *rettv); 115 static void f_cosh(typval_T *argvars, typval_T *rettv); 116 #endif 117 static void f_count(typval_T *argvars, typval_T *rettv); 118 static void f_cscope_connection(typval_T *argvars, typval_T *rettv); 119 static void f_cursor(typval_T *argsvars, typval_T *rettv); 120 static void f_deepcopy(typval_T *argvars, typval_T *rettv); 121 static void f_delete(typval_T *argvars, typval_T *rettv); 122 static void f_did_filetype(typval_T *argvars, typval_T *rettv); 123 static void f_diff_filler(typval_T *argvars, typval_T *rettv); 124 static void f_diff_hlID(typval_T *argvars, typval_T *rettv); 125 static void f_empty(typval_T *argvars, typval_T *rettv); 126 static void f_escape(typval_T *argvars, typval_T *rettv); 127 static void f_eval(typval_T *argvars, typval_T *rettv); 128 static void f_eventhandler(typval_T *argvars, typval_T *rettv); 129 static void f_executable(typval_T *argvars, typval_T *rettv); 130 static void f_execute(typval_T *argvars, typval_T *rettv); 131 static void f_exepath(typval_T *argvars, typval_T *rettv); 132 static void f_exists(typval_T *argvars, typval_T *rettv); 133 #ifdef FEAT_FLOAT 134 static void f_exp(typval_T *argvars, typval_T *rettv); 135 #endif 136 static void f_expand(typval_T *argvars, typval_T *rettv); 137 static void f_extend(typval_T *argvars, typval_T *rettv); 138 static void f_feedkeys(typval_T *argvars, typval_T *rettv); 139 static void f_filereadable(typval_T *argvars, typval_T *rettv); 140 static void f_filewritable(typval_T *argvars, typval_T *rettv); 141 static void f_filter(typval_T *argvars, typval_T *rettv); 142 static void f_finddir(typval_T *argvars, typval_T *rettv); 143 static void f_findfile(typval_T *argvars, typval_T *rettv); 144 #ifdef FEAT_FLOAT 145 static void f_float2nr(typval_T *argvars, typval_T *rettv); 146 static void f_floor(typval_T *argvars, typval_T *rettv); 147 static void f_fmod(typval_T *argvars, typval_T *rettv); 148 #endif 149 static void f_fnameescape(typval_T *argvars, typval_T *rettv); 150 static void f_fnamemodify(typval_T *argvars, typval_T *rettv); 151 static void f_foldclosed(typval_T *argvars, typval_T *rettv); 152 static void f_foldclosedend(typval_T *argvars, typval_T *rettv); 153 static void f_foldlevel(typval_T *argvars, typval_T *rettv); 154 static void f_foldtext(typval_T *argvars, typval_T *rettv); 155 static void f_foldtextresult(typval_T *argvars, typval_T *rettv); 156 static void f_foreground(typval_T *argvars, typval_T *rettv); 157 static void f_funcref(typval_T *argvars, typval_T *rettv); 158 static void f_function(typval_T *argvars, typval_T *rettv); 159 static void f_garbagecollect(typval_T *argvars, typval_T *rettv); 160 static void f_get(typval_T *argvars, typval_T *rettv); 161 static void f_getbufinfo(typval_T *argvars, typval_T *rettv); 162 static void f_getbufline(typval_T *argvars, typval_T *rettv); 163 static void f_getbufvar(typval_T *argvars, typval_T *rettv); 164 static void f_getchar(typval_T *argvars, typval_T *rettv); 165 static void f_getcharmod(typval_T *argvars, typval_T *rettv); 166 static void f_getcharsearch(typval_T *argvars, typval_T *rettv); 167 static void f_getcmdline(typval_T *argvars, typval_T *rettv); 168 #if defined(FEAT_CMDL_COMPL) 169 static void f_getcompletion(typval_T *argvars, typval_T *rettv); 170 #endif 171 static void f_getcmdpos(typval_T *argvars, typval_T *rettv); 172 static void f_getcmdtype(typval_T *argvars, typval_T *rettv); 173 static void f_getcmdwintype(typval_T *argvars, typval_T *rettv); 174 static void f_getcwd(typval_T *argvars, typval_T *rettv); 175 static void f_getfontname(typval_T *argvars, typval_T *rettv); 176 static void f_getfperm(typval_T *argvars, typval_T *rettv); 177 static void f_getfsize(typval_T *argvars, typval_T *rettv); 178 static void f_getftime(typval_T *argvars, typval_T *rettv); 179 static void f_getftype(typval_T *argvars, typval_T *rettv); 180 static void f_getline(typval_T *argvars, typval_T *rettv); 181 static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED); 182 static void f_getmatches(typval_T *argvars, typval_T *rettv); 183 static void f_getpid(typval_T *argvars, typval_T *rettv); 184 static void f_getcurpos(typval_T *argvars, typval_T *rettv); 185 static void f_getpos(typval_T *argvars, typval_T *rettv); 186 static void f_getqflist(typval_T *argvars, typval_T *rettv); 187 static void f_getreg(typval_T *argvars, typval_T *rettv); 188 static void f_getregtype(typval_T *argvars, typval_T *rettv); 189 static void f_gettabinfo(typval_T *argvars, typval_T *rettv); 190 static void f_gettabvar(typval_T *argvars, typval_T *rettv); 191 static void f_gettabwinvar(typval_T *argvars, typval_T *rettv); 192 static void f_getwininfo(typval_T *argvars, typval_T *rettv); 193 static void f_getwinposx(typval_T *argvars, typval_T *rettv); 194 static void f_getwinposy(typval_T *argvars, typval_T *rettv); 195 static void f_getwinvar(typval_T *argvars, typval_T *rettv); 196 static void f_glob(typval_T *argvars, typval_T *rettv); 197 static void f_globpath(typval_T *argvars, typval_T *rettv); 198 static void f_glob2regpat(typval_T *argvars, typval_T *rettv); 199 static void f_has(typval_T *argvars, typval_T *rettv); 200 static void f_has_key(typval_T *argvars, typval_T *rettv); 201 static void f_haslocaldir(typval_T *argvars, typval_T *rettv); 202 static void f_hasmapto(typval_T *argvars, typval_T *rettv); 203 static void f_histadd(typval_T *argvars, typval_T *rettv); 204 static void f_histdel(typval_T *argvars, typval_T *rettv); 205 static void f_histget(typval_T *argvars, typval_T *rettv); 206 static void f_histnr(typval_T *argvars, typval_T *rettv); 207 static void f_hlID(typval_T *argvars, typval_T *rettv); 208 static void f_hlexists(typval_T *argvars, typval_T *rettv); 209 static void f_hostname(typval_T *argvars, typval_T *rettv); 210 static void f_iconv(typval_T *argvars, typval_T *rettv); 211 static void f_indent(typval_T *argvars, typval_T *rettv); 212 static void f_index(typval_T *argvars, typval_T *rettv); 213 static void f_input(typval_T *argvars, typval_T *rettv); 214 static void f_inputdialog(typval_T *argvars, typval_T *rettv); 215 static void f_inputlist(typval_T *argvars, typval_T *rettv); 216 static void f_inputrestore(typval_T *argvars, typval_T *rettv); 217 static void f_inputsave(typval_T *argvars, typval_T *rettv); 218 static void f_inputsecret(typval_T *argvars, typval_T *rettv); 219 static void f_insert(typval_T *argvars, typval_T *rettv); 220 static void f_invert(typval_T *argvars, typval_T *rettv); 221 static void f_isdirectory(typval_T *argvars, typval_T *rettv); 222 static void f_islocked(typval_T *argvars, typval_T *rettv); 223 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) 224 static void f_isnan(typval_T *argvars, typval_T *rettv); 225 #endif 226 static void f_items(typval_T *argvars, typval_T *rettv); 227 #ifdef FEAT_JOB_CHANNEL 228 static void f_job_getchannel(typval_T *argvars, typval_T *rettv); 229 static void f_job_info(typval_T *argvars, typval_T *rettv); 230 static void f_job_setoptions(typval_T *argvars, typval_T *rettv); 231 static void f_job_start(typval_T *argvars, typval_T *rettv); 232 static void f_job_stop(typval_T *argvars, typval_T *rettv); 233 static void f_job_status(typval_T *argvars, typval_T *rettv); 234 #endif 235 static void f_join(typval_T *argvars, typval_T *rettv); 236 static void f_js_decode(typval_T *argvars, typval_T *rettv); 237 static void f_js_encode(typval_T *argvars, typval_T *rettv); 238 static void f_json_decode(typval_T *argvars, typval_T *rettv); 239 static void f_json_encode(typval_T *argvars, typval_T *rettv); 240 static void f_keys(typval_T *argvars, typval_T *rettv); 241 static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv); 242 static void f_len(typval_T *argvars, typval_T *rettv); 243 static void f_libcall(typval_T *argvars, typval_T *rettv); 244 static void f_libcallnr(typval_T *argvars, typval_T *rettv); 245 static void f_line(typval_T *argvars, typval_T *rettv); 246 static void f_line2byte(typval_T *argvars, typval_T *rettv); 247 static void f_lispindent(typval_T *argvars, typval_T *rettv); 248 static void f_localtime(typval_T *argvars, typval_T *rettv); 249 #ifdef FEAT_FLOAT 250 static void f_log(typval_T *argvars, typval_T *rettv); 251 static void f_log10(typval_T *argvars, typval_T *rettv); 252 #endif 253 #ifdef FEAT_LUA 254 static void f_luaeval(typval_T *argvars, typval_T *rettv); 255 #endif 256 static void f_map(typval_T *argvars, typval_T *rettv); 257 static void f_maparg(typval_T *argvars, typval_T *rettv); 258 static void f_mapcheck(typval_T *argvars, typval_T *rettv); 259 static void f_match(typval_T *argvars, typval_T *rettv); 260 static void f_matchadd(typval_T *argvars, typval_T *rettv); 261 static void f_matchaddpos(typval_T *argvars, typval_T *rettv); 262 static void f_matcharg(typval_T *argvars, typval_T *rettv); 263 static void f_matchdelete(typval_T *argvars, typval_T *rettv); 264 static void f_matchend(typval_T *argvars, typval_T *rettv); 265 static void f_matchlist(typval_T *argvars, typval_T *rettv); 266 static void f_matchstr(typval_T *argvars, typval_T *rettv); 267 static void f_matchstrpos(typval_T *argvars, typval_T *rettv); 268 static void f_max(typval_T *argvars, typval_T *rettv); 269 static void f_min(typval_T *argvars, typval_T *rettv); 270 #ifdef vim_mkdir 271 static void f_mkdir(typval_T *argvars, typval_T *rettv); 272 #endif 273 static void f_mode(typval_T *argvars, typval_T *rettv); 274 #ifdef FEAT_MZSCHEME 275 static void f_mzeval(typval_T *argvars, typval_T *rettv); 276 #endif 277 static void f_nextnonblank(typval_T *argvars, typval_T *rettv); 278 static void f_nr2char(typval_T *argvars, typval_T *rettv); 279 static void f_or(typval_T *argvars, typval_T *rettv); 280 static void f_pathshorten(typval_T *argvars, typval_T *rettv); 281 #ifdef FEAT_PERL 282 static void f_perleval(typval_T *argvars, typval_T *rettv); 283 #endif 284 #ifdef FEAT_FLOAT 285 static void f_pow(typval_T *argvars, typval_T *rettv); 286 #endif 287 static void f_prevnonblank(typval_T *argvars, typval_T *rettv); 288 static void f_printf(typval_T *argvars, typval_T *rettv); 289 static void f_pumvisible(typval_T *argvars, typval_T *rettv); 290 #ifdef FEAT_PYTHON3 291 static void f_py3eval(typval_T *argvars, typval_T *rettv); 292 #endif 293 #ifdef FEAT_PYTHON 294 static void f_pyeval(typval_T *argvars, typval_T *rettv); 295 #endif 296 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) 297 static void f_pyxeval(typval_T *argvars, typval_T *rettv); 298 #endif 299 static void f_range(typval_T *argvars, typval_T *rettv); 300 static void f_readfile(typval_T *argvars, typval_T *rettv); 301 static void f_reltime(typval_T *argvars, typval_T *rettv); 302 #ifdef FEAT_FLOAT 303 static void f_reltimefloat(typval_T *argvars, typval_T *rettv); 304 #endif 305 static void f_reltimestr(typval_T *argvars, typval_T *rettv); 306 static void f_remote_expr(typval_T *argvars, typval_T *rettv); 307 static void f_remote_foreground(typval_T *argvars, typval_T *rettv); 308 static void f_remote_peek(typval_T *argvars, typval_T *rettv); 309 static void f_remote_read(typval_T *argvars, typval_T *rettv); 310 static void f_remote_send(typval_T *argvars, typval_T *rettv); 311 static void f_remote_startserver(typval_T *argvars, typval_T *rettv); 312 static void f_remove(typval_T *argvars, typval_T *rettv); 313 static void f_rename(typval_T *argvars, typval_T *rettv); 314 static void f_repeat(typval_T *argvars, typval_T *rettv); 315 static void f_resolve(typval_T *argvars, typval_T *rettv); 316 static void f_reverse(typval_T *argvars, typval_T *rettv); 317 #ifdef FEAT_FLOAT 318 static void f_round(typval_T *argvars, typval_T *rettv); 319 #endif 320 static void f_screenattr(typval_T *argvars, typval_T *rettv); 321 static void f_screenchar(typval_T *argvars, typval_T *rettv); 322 static void f_screencol(typval_T *argvars, typval_T *rettv); 323 static void f_screenrow(typval_T *argvars, typval_T *rettv); 324 static void f_search(typval_T *argvars, typval_T *rettv); 325 static void f_searchdecl(typval_T *argvars, typval_T *rettv); 326 static void f_searchpair(typval_T *argvars, typval_T *rettv); 327 static void f_searchpairpos(typval_T *argvars, typval_T *rettv); 328 static void f_searchpos(typval_T *argvars, typval_T *rettv); 329 static void f_server2client(typval_T *argvars, typval_T *rettv); 330 static void f_serverlist(typval_T *argvars, typval_T *rettv); 331 static void f_setbufvar(typval_T *argvars, typval_T *rettv); 332 static void f_setcharsearch(typval_T *argvars, typval_T *rettv); 333 static void f_setcmdpos(typval_T *argvars, typval_T *rettv); 334 static void f_setfperm(typval_T *argvars, typval_T *rettv); 335 static void f_setline(typval_T *argvars, typval_T *rettv); 336 static void f_setloclist(typval_T *argvars, typval_T *rettv); 337 static void f_setmatches(typval_T *argvars, typval_T *rettv); 338 static void f_setpos(typval_T *argvars, typval_T *rettv); 339 static void f_setqflist(typval_T *argvars, typval_T *rettv); 340 static void f_setreg(typval_T *argvars, typval_T *rettv); 341 static void f_settabvar(typval_T *argvars, typval_T *rettv); 342 static void f_settabwinvar(typval_T *argvars, typval_T *rettv); 343 static void f_setwinvar(typval_T *argvars, typval_T *rettv); 344 #ifdef FEAT_CRYPT 345 static void f_sha256(typval_T *argvars, typval_T *rettv); 346 #endif /* FEAT_CRYPT */ 347 static void f_shellescape(typval_T *argvars, typval_T *rettv); 348 static void f_shiftwidth(typval_T *argvars, typval_T *rettv); 349 static void f_simplify(typval_T *argvars, typval_T *rettv); 350 #ifdef FEAT_FLOAT 351 static void f_sin(typval_T *argvars, typval_T *rettv); 352 static void f_sinh(typval_T *argvars, typval_T *rettv); 353 #endif 354 static void f_sort(typval_T *argvars, typval_T *rettv); 355 static void f_soundfold(typval_T *argvars, typval_T *rettv); 356 static void f_spellbadword(typval_T *argvars, typval_T *rettv); 357 static void f_spellsuggest(typval_T *argvars, typval_T *rettv); 358 static void f_split(typval_T *argvars, typval_T *rettv); 359 #ifdef FEAT_FLOAT 360 static void f_sqrt(typval_T *argvars, typval_T *rettv); 361 static void f_str2float(typval_T *argvars, typval_T *rettv); 362 #endif 363 static void f_str2nr(typval_T *argvars, typval_T *rettv); 364 static void f_strchars(typval_T *argvars, typval_T *rettv); 365 #ifdef HAVE_STRFTIME 366 static void f_strftime(typval_T *argvars, typval_T *rettv); 367 #endif 368 static void f_strgetchar(typval_T *argvars, typval_T *rettv); 369 static void f_stridx(typval_T *argvars, typval_T *rettv); 370 static void f_string(typval_T *argvars, typval_T *rettv); 371 static void f_strlen(typval_T *argvars, typval_T *rettv); 372 static void f_strcharpart(typval_T *argvars, typval_T *rettv); 373 static void f_strpart(typval_T *argvars, typval_T *rettv); 374 static void f_strridx(typval_T *argvars, typval_T *rettv); 375 static void f_strtrans(typval_T *argvars, typval_T *rettv); 376 static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv); 377 static void f_strwidth(typval_T *argvars, typval_T *rettv); 378 static void f_submatch(typval_T *argvars, typval_T *rettv); 379 static void f_substitute(typval_T *argvars, typval_T *rettv); 380 static void f_synID(typval_T *argvars, typval_T *rettv); 381 static void f_synIDattr(typval_T *argvars, typval_T *rettv); 382 static void f_synIDtrans(typval_T *argvars, typval_T *rettv); 383 static void f_synstack(typval_T *argvars, typval_T *rettv); 384 static void f_synconcealed(typval_T *argvars, typval_T *rettv); 385 static void f_system(typval_T *argvars, typval_T *rettv); 386 static void f_systemlist(typval_T *argvars, typval_T *rettv); 387 static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv); 388 static void f_tabpagenr(typval_T *argvars, typval_T *rettv); 389 static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv); 390 static void f_taglist(typval_T *argvars, typval_T *rettv); 391 static void f_tagfiles(typval_T *argvars, typval_T *rettv); 392 static void f_tempname(typval_T *argvars, typval_T *rettv); 393 static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv); 394 static void f_test_autochdir(typval_T *argvars, typval_T *rettv); 395 static void f_test_override(typval_T *argvars, typval_T *rettv); 396 static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv); 397 static void f_test_ignore_error(typval_T *argvars, typval_T *rettv); 398 #ifdef FEAT_JOB_CHANNEL 399 static void f_test_null_channel(typval_T *argvars, typval_T *rettv); 400 #endif 401 static void f_test_null_dict(typval_T *argvars, typval_T *rettv); 402 #ifdef FEAT_JOB_CHANNEL 403 static void f_test_null_job(typval_T *argvars, typval_T *rettv); 404 #endif 405 static void f_test_null_list(typval_T *argvars, typval_T *rettv); 406 static void f_test_null_partial(typval_T *argvars, typval_T *rettv); 407 static void f_test_null_string(typval_T *argvars, typval_T *rettv); 408 static void f_test_settime(typval_T *argvars, typval_T *rettv); 409 #ifdef FEAT_FLOAT 410 static void f_tan(typval_T *argvars, typval_T *rettv); 411 static void f_tanh(typval_T *argvars, typval_T *rettv); 412 #endif 413 #ifdef FEAT_TIMERS 414 static void f_timer_info(typval_T *argvars, typval_T *rettv); 415 static void f_timer_pause(typval_T *argvars, typval_T *rettv); 416 static void f_timer_start(typval_T *argvars, typval_T *rettv); 417 static void f_timer_stop(typval_T *argvars, typval_T *rettv); 418 static void f_timer_stopall(typval_T *argvars, typval_T *rettv); 419 #endif 420 static void f_tolower(typval_T *argvars, typval_T *rettv); 421 static void f_toupper(typval_T *argvars, typval_T *rettv); 422 static void f_tr(typval_T *argvars, typval_T *rettv); 423 #ifdef FEAT_FLOAT 424 static void f_trunc(typval_T *argvars, typval_T *rettv); 425 #endif 426 static void f_type(typval_T *argvars, typval_T *rettv); 427 static void f_undofile(typval_T *argvars, typval_T *rettv); 428 static void f_undotree(typval_T *argvars, typval_T *rettv); 429 static void f_uniq(typval_T *argvars, typval_T *rettv); 430 static void f_values(typval_T *argvars, typval_T *rettv); 431 static void f_virtcol(typval_T *argvars, typval_T *rettv); 432 static void f_visualmode(typval_T *argvars, typval_T *rettv); 433 static void f_wildmenumode(typval_T *argvars, typval_T *rettv); 434 static void f_win_findbuf(typval_T *argvars, typval_T *rettv); 435 static void f_win_getid(typval_T *argvars, typval_T *rettv); 436 static void f_win_gotoid(typval_T *argvars, typval_T *rettv); 437 static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv); 438 static void f_win_id2win(typval_T *argvars, typval_T *rettv); 439 static void f_winbufnr(typval_T *argvars, typval_T *rettv); 440 static void f_wincol(typval_T *argvars, typval_T *rettv); 441 static void f_winheight(typval_T *argvars, typval_T *rettv); 442 static void f_winline(typval_T *argvars, typval_T *rettv); 443 static void f_winnr(typval_T *argvars, typval_T *rettv); 444 static void f_winrestcmd(typval_T *argvars, typval_T *rettv); 445 static void f_winrestview(typval_T *argvars, typval_T *rettv); 446 static void f_winsaveview(typval_T *argvars, typval_T *rettv); 447 static void f_winwidth(typval_T *argvars, typval_T *rettv); 448 static void f_writefile(typval_T *argvars, typval_T *rettv); 449 static void f_wordcount(typval_T *argvars, typval_T *rettv); 450 static void f_xor(typval_T *argvars, typval_T *rettv); 451 452 /* 453 * Array with names and number of arguments of all internal functions 454 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH! 455 */ 456 static struct fst 457 { 458 char *f_name; /* function name */ 459 char f_min_argc; /* minimal number of arguments */ 460 char f_max_argc; /* maximal number of arguments */ 461 void (*f_func)(typval_T *args, typval_T *rvar); 462 /* implementation of function */ 463 } functions[] = 464 { 465 #ifdef FEAT_FLOAT 466 {"abs", 1, 1, f_abs}, 467 {"acos", 1, 1, f_acos}, /* WJMc */ 468 #endif 469 {"add", 2, 2, f_add}, 470 {"and", 2, 2, f_and}, 471 {"append", 2, 2, f_append}, 472 {"argc", 0, 0, f_argc}, 473 {"argidx", 0, 0, f_argidx}, 474 {"arglistid", 0, 2, f_arglistid}, 475 {"argv", 0, 1, f_argv}, 476 #ifdef FEAT_FLOAT 477 {"asin", 1, 1, f_asin}, /* WJMc */ 478 #endif 479 {"assert_equal", 2, 3, f_assert_equal}, 480 {"assert_exception", 1, 2, f_assert_exception}, 481 {"assert_fails", 1, 2, f_assert_fails}, 482 {"assert_false", 1, 2, f_assert_false}, 483 {"assert_inrange", 3, 4, f_assert_inrange}, 484 {"assert_match", 2, 3, f_assert_match}, 485 {"assert_notequal", 2, 3, f_assert_notequal}, 486 {"assert_notmatch", 2, 3, f_assert_notmatch}, 487 {"assert_report", 1, 1, f_assert_report}, 488 {"assert_true", 1, 2, f_assert_true}, 489 #ifdef FEAT_FLOAT 490 {"atan", 1, 1, f_atan}, 491 {"atan2", 2, 2, f_atan2}, 492 #endif 493 #ifdef FEAT_BEVAL 494 {"balloon_show", 1, 1, f_balloon_show}, 495 #endif 496 {"browse", 4, 4, f_browse}, 497 {"browsedir", 2, 2, f_browsedir}, 498 {"bufexists", 1, 1, f_bufexists}, 499 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */ 500 {"buffer_name", 1, 1, f_bufname}, /* obsolete */ 501 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */ 502 {"buflisted", 1, 1, f_buflisted}, 503 {"bufloaded", 1, 1, f_bufloaded}, 504 {"bufname", 1, 1, f_bufname}, 505 {"bufnr", 1, 2, f_bufnr}, 506 {"bufwinid", 1, 1, f_bufwinid}, 507 {"bufwinnr", 1, 1, f_bufwinnr}, 508 {"byte2line", 1, 1, f_byte2line}, 509 {"byteidx", 2, 2, f_byteidx}, 510 {"byteidxcomp", 2, 2, f_byteidxcomp}, 511 {"call", 2, 3, f_call}, 512 #ifdef FEAT_FLOAT 513 {"ceil", 1, 1, f_ceil}, 514 #endif 515 #ifdef FEAT_JOB_CHANNEL 516 {"ch_canread", 1, 1, f_ch_canread}, 517 {"ch_close", 1, 1, f_ch_close}, 518 {"ch_close_in", 1, 1, f_ch_close_in}, 519 {"ch_evalexpr", 2, 3, f_ch_evalexpr}, 520 {"ch_evalraw", 2, 3, f_ch_evalraw}, 521 {"ch_getbufnr", 2, 2, f_ch_getbufnr}, 522 {"ch_getjob", 1, 1, f_ch_getjob}, 523 {"ch_info", 1, 1, f_ch_info}, 524 {"ch_log", 1, 2, f_ch_log}, 525 {"ch_logfile", 1, 2, f_ch_logfile}, 526 {"ch_open", 1, 2, f_ch_open}, 527 {"ch_read", 1, 2, f_ch_read}, 528 {"ch_readraw", 1, 2, f_ch_readraw}, 529 {"ch_sendexpr", 2, 3, f_ch_sendexpr}, 530 {"ch_sendraw", 2, 3, f_ch_sendraw}, 531 {"ch_setoptions", 2, 2, f_ch_setoptions}, 532 {"ch_status", 1, 2, f_ch_status}, 533 #endif 534 {"changenr", 0, 0, f_changenr}, 535 {"char2nr", 1, 2, f_char2nr}, 536 {"cindent", 1, 1, f_cindent}, 537 {"clearmatches", 0, 0, f_clearmatches}, 538 {"col", 1, 1, f_col}, 539 #if defined(FEAT_INS_EXPAND) 540 {"complete", 2, 2, f_complete}, 541 {"complete_add", 1, 1, f_complete_add}, 542 {"complete_check", 0, 0, f_complete_check}, 543 #endif 544 {"confirm", 1, 4, f_confirm}, 545 {"copy", 1, 1, f_copy}, 546 #ifdef FEAT_FLOAT 547 {"cos", 1, 1, f_cos}, 548 {"cosh", 1, 1, f_cosh}, 549 #endif 550 {"count", 2, 4, f_count}, 551 {"cscope_connection",0,3, f_cscope_connection}, 552 {"cursor", 1, 3, f_cursor}, 553 {"deepcopy", 1, 2, f_deepcopy}, 554 {"delete", 1, 2, f_delete}, 555 {"did_filetype", 0, 0, f_did_filetype}, 556 {"diff_filler", 1, 1, f_diff_filler}, 557 {"diff_hlID", 2, 2, f_diff_hlID}, 558 {"empty", 1, 1, f_empty}, 559 {"escape", 2, 2, f_escape}, 560 {"eval", 1, 1, f_eval}, 561 {"eventhandler", 0, 0, f_eventhandler}, 562 {"executable", 1, 1, f_executable}, 563 {"execute", 1, 2, f_execute}, 564 {"exepath", 1, 1, f_exepath}, 565 {"exists", 1, 1, f_exists}, 566 #ifdef FEAT_FLOAT 567 {"exp", 1, 1, f_exp}, 568 #endif 569 {"expand", 1, 3, f_expand}, 570 {"extend", 2, 3, f_extend}, 571 {"feedkeys", 1, 2, f_feedkeys}, 572 {"file_readable", 1, 1, f_filereadable}, /* obsolete */ 573 {"filereadable", 1, 1, f_filereadable}, 574 {"filewritable", 1, 1, f_filewritable}, 575 {"filter", 2, 2, f_filter}, 576 {"finddir", 1, 3, f_finddir}, 577 {"findfile", 1, 3, f_findfile}, 578 #ifdef FEAT_FLOAT 579 {"float2nr", 1, 1, f_float2nr}, 580 {"floor", 1, 1, f_floor}, 581 {"fmod", 2, 2, f_fmod}, 582 #endif 583 {"fnameescape", 1, 1, f_fnameescape}, 584 {"fnamemodify", 2, 2, f_fnamemodify}, 585 {"foldclosed", 1, 1, f_foldclosed}, 586 {"foldclosedend", 1, 1, f_foldclosedend}, 587 {"foldlevel", 1, 1, f_foldlevel}, 588 {"foldtext", 0, 0, f_foldtext}, 589 {"foldtextresult", 1, 1, f_foldtextresult}, 590 {"foreground", 0, 0, f_foreground}, 591 {"funcref", 1, 3, f_funcref}, 592 {"function", 1, 3, f_function}, 593 {"garbagecollect", 0, 1, f_garbagecollect}, 594 {"get", 2, 3, f_get}, 595 {"getbufinfo", 0, 1, f_getbufinfo}, 596 {"getbufline", 2, 3, f_getbufline}, 597 {"getbufvar", 2, 3, f_getbufvar}, 598 {"getchar", 0, 1, f_getchar}, 599 {"getcharmod", 0, 0, f_getcharmod}, 600 {"getcharsearch", 0, 0, f_getcharsearch}, 601 {"getcmdline", 0, 0, f_getcmdline}, 602 {"getcmdpos", 0, 0, f_getcmdpos}, 603 {"getcmdtype", 0, 0, f_getcmdtype}, 604 {"getcmdwintype", 0, 0, f_getcmdwintype}, 605 #if defined(FEAT_CMDL_COMPL) 606 {"getcompletion", 2, 3, f_getcompletion}, 607 #endif 608 {"getcurpos", 0, 0, f_getcurpos}, 609 {"getcwd", 0, 2, f_getcwd}, 610 {"getfontname", 0, 1, f_getfontname}, 611 {"getfperm", 1, 1, f_getfperm}, 612 {"getfsize", 1, 1, f_getfsize}, 613 {"getftime", 1, 1, f_getftime}, 614 {"getftype", 1, 1, f_getftype}, 615 {"getline", 1, 2, f_getline}, 616 {"getloclist", 1, 2, f_getloclist}, 617 {"getmatches", 0, 0, f_getmatches}, 618 {"getpid", 0, 0, f_getpid}, 619 {"getpos", 1, 1, f_getpos}, 620 {"getqflist", 0, 1, f_getqflist}, 621 {"getreg", 0, 3, f_getreg}, 622 {"getregtype", 0, 1, f_getregtype}, 623 {"gettabinfo", 0, 1, f_gettabinfo}, 624 {"gettabvar", 2, 3, f_gettabvar}, 625 {"gettabwinvar", 3, 4, f_gettabwinvar}, 626 {"getwininfo", 0, 1, f_getwininfo}, 627 {"getwinposx", 0, 0, f_getwinposx}, 628 {"getwinposy", 0, 0, f_getwinposy}, 629 {"getwinvar", 2, 3, f_getwinvar}, 630 {"glob", 1, 4, f_glob}, 631 {"glob2regpat", 1, 1, f_glob2regpat}, 632 {"globpath", 2, 5, f_globpath}, 633 {"has", 1, 1, f_has}, 634 {"has_key", 2, 2, f_has_key}, 635 {"haslocaldir", 0, 2, f_haslocaldir}, 636 {"hasmapto", 1, 3, f_hasmapto}, 637 {"highlightID", 1, 1, f_hlID}, /* obsolete */ 638 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */ 639 {"histadd", 2, 2, f_histadd}, 640 {"histdel", 1, 2, f_histdel}, 641 {"histget", 1, 2, f_histget}, 642 {"histnr", 1, 1, f_histnr}, 643 {"hlID", 1, 1, f_hlID}, 644 {"hlexists", 1, 1, f_hlexists}, 645 {"hostname", 0, 0, f_hostname}, 646 {"iconv", 3, 3, f_iconv}, 647 {"indent", 1, 1, f_indent}, 648 {"index", 2, 4, f_index}, 649 {"input", 1, 3, f_input}, 650 {"inputdialog", 1, 3, f_inputdialog}, 651 {"inputlist", 1, 1, f_inputlist}, 652 {"inputrestore", 0, 0, f_inputrestore}, 653 {"inputsave", 0, 0, f_inputsave}, 654 {"inputsecret", 1, 2, f_inputsecret}, 655 {"insert", 2, 3, f_insert}, 656 {"invert", 1, 1, f_invert}, 657 {"isdirectory", 1, 1, f_isdirectory}, 658 {"islocked", 1, 1, f_islocked}, 659 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) 660 {"isnan", 1, 1, f_isnan}, 661 #endif 662 {"items", 1, 1, f_items}, 663 #ifdef FEAT_JOB_CHANNEL 664 {"job_getchannel", 1, 1, f_job_getchannel}, 665 {"job_info", 1, 1, f_job_info}, 666 {"job_setoptions", 2, 2, f_job_setoptions}, 667 {"job_start", 1, 2, f_job_start}, 668 {"job_status", 1, 1, f_job_status}, 669 {"job_stop", 1, 2, f_job_stop}, 670 #endif 671 {"join", 1, 2, f_join}, 672 {"js_decode", 1, 1, f_js_decode}, 673 {"js_encode", 1, 1, f_js_encode}, 674 {"json_decode", 1, 1, f_json_decode}, 675 {"json_encode", 1, 1, f_json_encode}, 676 {"keys", 1, 1, f_keys}, 677 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */ 678 {"len", 1, 1, f_len}, 679 {"libcall", 3, 3, f_libcall}, 680 {"libcallnr", 3, 3, f_libcallnr}, 681 {"line", 1, 1, f_line}, 682 {"line2byte", 1, 1, f_line2byte}, 683 {"lispindent", 1, 1, f_lispindent}, 684 {"localtime", 0, 0, f_localtime}, 685 #ifdef FEAT_FLOAT 686 {"log", 1, 1, f_log}, 687 {"log10", 1, 1, f_log10}, 688 #endif 689 #ifdef FEAT_LUA 690 {"luaeval", 1, 2, f_luaeval}, 691 #endif 692 {"map", 2, 2, f_map}, 693 {"maparg", 1, 4, f_maparg}, 694 {"mapcheck", 1, 3, f_mapcheck}, 695 {"match", 2, 4, f_match}, 696 {"matchadd", 2, 5, f_matchadd}, 697 {"matchaddpos", 2, 5, f_matchaddpos}, 698 {"matcharg", 1, 1, f_matcharg}, 699 {"matchdelete", 1, 1, f_matchdelete}, 700 {"matchend", 2, 4, f_matchend}, 701 {"matchlist", 2, 4, f_matchlist}, 702 {"matchstr", 2, 4, f_matchstr}, 703 {"matchstrpos", 2, 4, f_matchstrpos}, 704 {"max", 1, 1, f_max}, 705 {"min", 1, 1, f_min}, 706 #ifdef vim_mkdir 707 {"mkdir", 1, 3, f_mkdir}, 708 #endif 709 {"mode", 0, 1, f_mode}, 710 #ifdef FEAT_MZSCHEME 711 {"mzeval", 1, 1, f_mzeval}, 712 #endif 713 {"nextnonblank", 1, 1, f_nextnonblank}, 714 {"nr2char", 1, 2, f_nr2char}, 715 {"or", 2, 2, f_or}, 716 {"pathshorten", 1, 1, f_pathshorten}, 717 #ifdef FEAT_PERL 718 {"perleval", 1, 1, f_perleval}, 719 #endif 720 #ifdef FEAT_FLOAT 721 {"pow", 2, 2, f_pow}, 722 #endif 723 {"prevnonblank", 1, 1, f_prevnonblank}, 724 {"printf", 2, 19, f_printf}, 725 {"pumvisible", 0, 0, f_pumvisible}, 726 #ifdef FEAT_PYTHON3 727 {"py3eval", 1, 1, f_py3eval}, 728 #endif 729 #ifdef FEAT_PYTHON 730 {"pyeval", 1, 1, f_pyeval}, 731 #endif 732 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) 733 {"pyxeval", 1, 1, f_pyxeval}, 734 #endif 735 {"range", 1, 3, f_range}, 736 {"readfile", 1, 3, f_readfile}, 737 {"reltime", 0, 2, f_reltime}, 738 #ifdef FEAT_FLOAT 739 {"reltimefloat", 1, 1, f_reltimefloat}, 740 #endif 741 {"reltimestr", 1, 1, f_reltimestr}, 742 {"remote_expr", 2, 4, f_remote_expr}, 743 {"remote_foreground", 1, 1, f_remote_foreground}, 744 {"remote_peek", 1, 2, f_remote_peek}, 745 {"remote_read", 1, 2, f_remote_read}, 746 {"remote_send", 2, 3, f_remote_send}, 747 {"remote_startserver", 1, 1, f_remote_startserver}, 748 {"remove", 2, 3, f_remove}, 749 {"rename", 2, 2, f_rename}, 750 {"repeat", 2, 2, f_repeat}, 751 {"resolve", 1, 1, f_resolve}, 752 {"reverse", 1, 1, f_reverse}, 753 #ifdef FEAT_FLOAT 754 {"round", 1, 1, f_round}, 755 #endif 756 {"screenattr", 2, 2, f_screenattr}, 757 {"screenchar", 2, 2, f_screenchar}, 758 {"screencol", 0, 0, f_screencol}, 759 {"screenrow", 0, 0, f_screenrow}, 760 {"search", 1, 4, f_search}, 761 {"searchdecl", 1, 3, f_searchdecl}, 762 {"searchpair", 3, 7, f_searchpair}, 763 {"searchpairpos", 3, 7, f_searchpairpos}, 764 {"searchpos", 1, 4, f_searchpos}, 765 {"server2client", 2, 2, f_server2client}, 766 {"serverlist", 0, 0, f_serverlist}, 767 {"setbufvar", 3, 3, f_setbufvar}, 768 {"setcharsearch", 1, 1, f_setcharsearch}, 769 {"setcmdpos", 1, 1, f_setcmdpos}, 770 {"setfperm", 2, 2, f_setfperm}, 771 {"setline", 2, 2, f_setline}, 772 {"setloclist", 2, 4, f_setloclist}, 773 {"setmatches", 1, 1, f_setmatches}, 774 {"setpos", 2, 2, f_setpos}, 775 {"setqflist", 1, 3, f_setqflist}, 776 {"setreg", 2, 3, f_setreg}, 777 {"settabvar", 3, 3, f_settabvar}, 778 {"settabwinvar", 4, 4, f_settabwinvar}, 779 {"setwinvar", 3, 3, f_setwinvar}, 780 #ifdef FEAT_CRYPT 781 {"sha256", 1, 1, f_sha256}, 782 #endif 783 {"shellescape", 1, 2, f_shellescape}, 784 {"shiftwidth", 0, 0, f_shiftwidth}, 785 {"simplify", 1, 1, f_simplify}, 786 #ifdef FEAT_FLOAT 787 {"sin", 1, 1, f_sin}, 788 {"sinh", 1, 1, f_sinh}, 789 #endif 790 {"sort", 1, 3, f_sort}, 791 {"soundfold", 1, 1, f_soundfold}, 792 {"spellbadword", 0, 1, f_spellbadword}, 793 {"spellsuggest", 1, 3, f_spellsuggest}, 794 {"split", 1, 3, f_split}, 795 #ifdef FEAT_FLOAT 796 {"sqrt", 1, 1, f_sqrt}, 797 {"str2float", 1, 1, f_str2float}, 798 #endif 799 {"str2nr", 1, 2, f_str2nr}, 800 {"strcharpart", 2, 3, f_strcharpart}, 801 {"strchars", 1, 2, f_strchars}, 802 {"strdisplaywidth", 1, 2, f_strdisplaywidth}, 803 #ifdef HAVE_STRFTIME 804 {"strftime", 1, 2, f_strftime}, 805 #endif 806 {"strgetchar", 2, 2, f_strgetchar}, 807 {"stridx", 2, 3, f_stridx}, 808 {"string", 1, 1, f_string}, 809 {"strlen", 1, 1, f_strlen}, 810 {"strpart", 2, 3, f_strpart}, 811 {"strridx", 2, 3, f_strridx}, 812 {"strtrans", 1, 1, f_strtrans}, 813 {"strwidth", 1, 1, f_strwidth}, 814 {"submatch", 1, 2, f_submatch}, 815 {"substitute", 4, 4, f_substitute}, 816 {"synID", 3, 3, f_synID}, 817 {"synIDattr", 2, 3, f_synIDattr}, 818 {"synIDtrans", 1, 1, f_synIDtrans}, 819 {"synconcealed", 2, 2, f_synconcealed}, 820 {"synstack", 2, 2, f_synstack}, 821 {"system", 1, 2, f_system}, 822 {"systemlist", 1, 2, f_systemlist}, 823 {"tabpagebuflist", 0, 1, f_tabpagebuflist}, 824 {"tabpagenr", 0, 1, f_tabpagenr}, 825 {"tabpagewinnr", 1, 2, f_tabpagewinnr}, 826 {"tagfiles", 0, 0, f_tagfiles}, 827 {"taglist", 1, 2, f_taglist}, 828 #ifdef FEAT_FLOAT 829 {"tan", 1, 1, f_tan}, 830 {"tanh", 1, 1, f_tanh}, 831 #endif 832 {"tempname", 0, 0, f_tempname}, 833 #ifdef FEAT_TERMINAL 834 {"term_getattr", 2, 2, f_term_getattr}, 835 {"term_getcursor", 1, 1, f_term_getcursor}, 836 {"term_getjob", 1, 1, f_term_getjob}, 837 {"term_getline", 1, 2, f_term_getline}, 838 {"term_getsize", 1, 1, f_term_getsize}, 839 {"term_getstatus", 1, 1, f_term_getstatus}, 840 {"term_gettitle", 1, 1, f_term_gettitle}, 841 {"term_gettty", 1, 1, f_term_gettty}, 842 {"term_list", 0, 0, f_term_list}, 843 {"term_scrape", 1, 2, f_term_scrape}, 844 {"term_sendkeys", 2, 2, f_term_sendkeys}, 845 {"term_start", 1, 2, f_term_start}, 846 {"term_wait", 1, 1, f_term_wait}, 847 #endif 848 {"test_alloc_fail", 3, 3, f_test_alloc_fail}, 849 {"test_autochdir", 0, 0, f_test_autochdir}, 850 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now}, 851 {"test_ignore_error", 1, 1, f_test_ignore_error}, 852 #ifdef FEAT_JOB_CHANNEL 853 {"test_null_channel", 0, 0, f_test_null_channel}, 854 #endif 855 {"test_null_dict", 0, 0, f_test_null_dict}, 856 #ifdef FEAT_JOB_CHANNEL 857 {"test_null_job", 0, 0, f_test_null_job}, 858 #endif 859 {"test_null_list", 0, 0, f_test_null_list}, 860 {"test_null_partial", 0, 0, f_test_null_partial}, 861 {"test_null_string", 0, 0, f_test_null_string}, 862 {"test_override", 2, 2, f_test_override}, 863 {"test_settime", 1, 1, f_test_settime}, 864 #ifdef FEAT_TIMERS 865 {"timer_info", 0, 1, f_timer_info}, 866 {"timer_pause", 2, 2, f_timer_pause}, 867 {"timer_start", 2, 3, f_timer_start}, 868 {"timer_stop", 1, 1, f_timer_stop}, 869 {"timer_stopall", 0, 0, f_timer_stopall}, 870 #endif 871 {"tolower", 1, 1, f_tolower}, 872 {"toupper", 1, 1, f_toupper}, 873 {"tr", 3, 3, f_tr}, 874 #ifdef FEAT_FLOAT 875 {"trunc", 1, 1, f_trunc}, 876 #endif 877 {"type", 1, 1, f_type}, 878 {"undofile", 1, 1, f_undofile}, 879 {"undotree", 0, 0, f_undotree}, 880 {"uniq", 1, 3, f_uniq}, 881 {"values", 1, 1, f_values}, 882 {"virtcol", 1, 1, f_virtcol}, 883 {"visualmode", 0, 1, f_visualmode}, 884 {"wildmenumode", 0, 0, f_wildmenumode}, 885 {"win_findbuf", 1, 1, f_win_findbuf}, 886 {"win_getid", 0, 2, f_win_getid}, 887 {"win_gotoid", 1, 1, f_win_gotoid}, 888 {"win_id2tabwin", 1, 1, f_win_id2tabwin}, 889 {"win_id2win", 1, 1, f_win_id2win}, 890 {"winbufnr", 1, 1, f_winbufnr}, 891 {"wincol", 0, 0, f_wincol}, 892 {"winheight", 1, 1, f_winheight}, 893 {"winline", 0, 0, f_winline}, 894 {"winnr", 0, 1, f_winnr}, 895 {"winrestcmd", 0, 0, f_winrestcmd}, 896 {"winrestview", 1, 1, f_winrestview}, 897 {"winsaveview", 0, 0, f_winsaveview}, 898 {"winwidth", 1, 1, f_winwidth}, 899 {"wordcount", 0, 0, f_wordcount}, 900 {"writefile", 2, 3, f_writefile}, 901 {"xor", 2, 2, f_xor}, 902 }; 903 904 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 905 906 /* 907 * Function given to ExpandGeneric() to obtain the list of internal 908 * or user defined function names. 909 */ 910 char_u * 911 get_function_name(expand_T *xp, int idx) 912 { 913 static int intidx = -1; 914 char_u *name; 915 916 if (idx == 0) 917 intidx = -1; 918 if (intidx < 0) 919 { 920 name = get_user_func_name(xp, idx); 921 if (name != NULL) 922 return name; 923 } 924 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst))) 925 { 926 STRCPY(IObuff, functions[intidx].f_name); 927 STRCAT(IObuff, "("); 928 if (functions[intidx].f_max_argc == 0) 929 STRCAT(IObuff, ")"); 930 return IObuff; 931 } 932 933 return NULL; 934 } 935 936 /* 937 * Function given to ExpandGeneric() to obtain the list of internal or 938 * user defined variable or function names. 939 */ 940 char_u * 941 get_expr_name(expand_T *xp, int idx) 942 { 943 static int intidx = -1; 944 char_u *name; 945 946 if (idx == 0) 947 intidx = -1; 948 if (intidx < 0) 949 { 950 name = get_function_name(xp, idx); 951 if (name != NULL) 952 return name; 953 } 954 return get_user_var_name(xp, ++intidx); 955 } 956 957 #endif /* FEAT_CMDL_COMPL */ 958 959 /* 960 * Find internal function in table above. 961 * Return index, or -1 if not found 962 */ 963 int 964 find_internal_func( 965 char_u *name) /* name of the function */ 966 { 967 int first = 0; 968 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1; 969 int cmp; 970 int x; 971 972 /* 973 * Find the function name in the table. Binary search. 974 */ 975 while (first <= last) 976 { 977 x = first + ((unsigned)(last - first) >> 1); 978 cmp = STRCMP(name, functions[x].f_name); 979 if (cmp < 0) 980 last = x - 1; 981 else if (cmp > 0) 982 first = x + 1; 983 else 984 return x; 985 } 986 return -1; 987 } 988 989 int 990 call_internal_func( 991 char_u *name, 992 int argcount, 993 typval_T *argvars, 994 typval_T *rettv) 995 { 996 int i; 997 998 i = find_internal_func(name); 999 if (i < 0) 1000 return ERROR_UNKNOWN; 1001 if (argcount < functions[i].f_min_argc) 1002 return ERROR_TOOFEW; 1003 if (argcount > functions[i].f_max_argc) 1004 return ERROR_TOOMANY; 1005 argvars[argcount].v_type = VAR_UNKNOWN; 1006 functions[i].f_func(argvars, rettv); 1007 return ERROR_NONE; 1008 } 1009 1010 /* 1011 * Return TRUE for a non-zero Number and a non-empty String. 1012 */ 1013 static int 1014 non_zero_arg(typval_T *argvars) 1015 { 1016 return ((argvars[0].v_type == VAR_NUMBER 1017 && argvars[0].vval.v_number != 0) 1018 || (argvars[0].v_type == VAR_SPECIAL 1019 && argvars[0].vval.v_number == VVAL_TRUE) 1020 || (argvars[0].v_type == VAR_STRING 1021 && argvars[0].vval.v_string != NULL 1022 && *argvars[0].vval.v_string != NUL)); 1023 } 1024 1025 /* 1026 * Get the lnum from the first argument. 1027 * Also accepts ".", "$", etc., but that only works for the current buffer. 1028 * Returns -1 on error. 1029 */ 1030 static linenr_T 1031 get_tv_lnum(typval_T *argvars) 1032 { 1033 typval_T rettv; 1034 linenr_T lnum; 1035 1036 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL); 1037 if (lnum == 0) /* no valid number, try using line() */ 1038 { 1039 rettv.v_type = VAR_NUMBER; 1040 f_line(argvars, &rettv); 1041 lnum = (linenr_T)rettv.vval.v_number; 1042 clear_tv(&rettv); 1043 } 1044 return lnum; 1045 } 1046 1047 #ifdef FEAT_FLOAT 1048 static int get_float_arg(typval_T *argvars, float_T *f); 1049 1050 /* 1051 * Get the float value of "argvars[0]" into "f". 1052 * Returns FAIL when the argument is not a Number or Float. 1053 */ 1054 static int 1055 get_float_arg(typval_T *argvars, float_T *f) 1056 { 1057 if (argvars[0].v_type == VAR_FLOAT) 1058 { 1059 *f = argvars[0].vval.v_float; 1060 return OK; 1061 } 1062 if (argvars[0].v_type == VAR_NUMBER) 1063 { 1064 *f = (float_T)argvars[0].vval.v_number; 1065 return OK; 1066 } 1067 EMSG(_("E808: Number or Float required")); 1068 return FAIL; 1069 } 1070 1071 /* 1072 * "abs(expr)" function 1073 */ 1074 static void 1075 f_abs(typval_T *argvars, typval_T *rettv) 1076 { 1077 if (argvars[0].v_type == VAR_FLOAT) 1078 { 1079 rettv->v_type = VAR_FLOAT; 1080 rettv->vval.v_float = fabs(argvars[0].vval.v_float); 1081 } 1082 else 1083 { 1084 varnumber_T n; 1085 int error = FALSE; 1086 1087 n = get_tv_number_chk(&argvars[0], &error); 1088 if (error) 1089 rettv->vval.v_number = -1; 1090 else if (n > 0) 1091 rettv->vval.v_number = n; 1092 else 1093 rettv->vval.v_number = -n; 1094 } 1095 } 1096 1097 /* 1098 * "acos()" function 1099 */ 1100 static void 1101 f_acos(typval_T *argvars, typval_T *rettv) 1102 { 1103 float_T f = 0.0; 1104 1105 rettv->v_type = VAR_FLOAT; 1106 if (get_float_arg(argvars, &f) == OK) 1107 rettv->vval.v_float = acos(f); 1108 else 1109 rettv->vval.v_float = 0.0; 1110 } 1111 #endif 1112 1113 /* 1114 * "add(list, item)" function 1115 */ 1116 static void 1117 f_add(typval_T *argvars, typval_T *rettv) 1118 { 1119 list_T *l; 1120 1121 rettv->vval.v_number = 1; /* Default: Failed */ 1122 if (argvars[0].v_type == VAR_LIST) 1123 { 1124 if ((l = argvars[0].vval.v_list) != NULL 1125 && !tv_check_lock(l->lv_lock, 1126 (char_u *)N_("add() argument"), TRUE) 1127 && list_append_tv(l, &argvars[1]) == OK) 1128 copy_tv(&argvars[0], rettv); 1129 } 1130 else 1131 EMSG(_(e_listreq)); 1132 } 1133 1134 /* 1135 * "and(expr, expr)" function 1136 */ 1137 static void 1138 f_and(typval_T *argvars, typval_T *rettv) 1139 { 1140 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) 1141 & get_tv_number_chk(&argvars[1], NULL); 1142 } 1143 1144 /* 1145 * "append(lnum, string/list)" function 1146 */ 1147 static void 1148 f_append(typval_T *argvars, typval_T *rettv) 1149 { 1150 long lnum; 1151 char_u *line; 1152 list_T *l = NULL; 1153 listitem_T *li = NULL; 1154 typval_T *tv; 1155 long added = 0; 1156 1157 /* When coming here from Insert mode, sync undo, so that this can be 1158 * undone separately from what was previously inserted. */ 1159 if (u_sync_once == 2) 1160 { 1161 u_sync_once = 1; /* notify that u_sync() was called */ 1162 u_sync(TRUE); 1163 } 1164 1165 lnum = get_tv_lnum(argvars); 1166 if (lnum >= 0 1167 && lnum <= curbuf->b_ml.ml_line_count 1168 && u_save(lnum, lnum + 1) == OK) 1169 { 1170 if (argvars[1].v_type == VAR_LIST) 1171 { 1172 l = argvars[1].vval.v_list; 1173 if (l == NULL) 1174 return; 1175 li = l->lv_first; 1176 } 1177 for (;;) 1178 { 1179 if (l == NULL) 1180 tv = &argvars[1]; /* append a string */ 1181 else if (li == NULL) 1182 break; /* end of list */ 1183 else 1184 tv = &li->li_tv; /* append item from list */ 1185 line = get_tv_string_chk(tv); 1186 if (line == NULL) /* type error */ 1187 { 1188 rettv->vval.v_number = 1; /* Failed */ 1189 break; 1190 } 1191 ml_append(lnum + added, line, (colnr_T)0, FALSE); 1192 ++added; 1193 if (l == NULL) 1194 break; 1195 li = li->li_next; 1196 } 1197 1198 appended_lines_mark(lnum, added); 1199 if (curwin->w_cursor.lnum > lnum) 1200 curwin->w_cursor.lnum += added; 1201 } 1202 else 1203 rettv->vval.v_number = 1; /* Failed */ 1204 } 1205 1206 /* 1207 * "argc()" function 1208 */ 1209 static void 1210 f_argc(typval_T *argvars UNUSED, typval_T *rettv) 1211 { 1212 rettv->vval.v_number = ARGCOUNT; 1213 } 1214 1215 /* 1216 * "argidx()" function 1217 */ 1218 static void 1219 f_argidx(typval_T *argvars UNUSED, typval_T *rettv) 1220 { 1221 rettv->vval.v_number = curwin->w_arg_idx; 1222 } 1223 1224 /* 1225 * "arglistid()" function 1226 */ 1227 static void 1228 f_arglistid(typval_T *argvars, typval_T *rettv) 1229 { 1230 win_T *wp; 1231 1232 rettv->vval.v_number = -1; 1233 wp = find_tabwin(&argvars[0], &argvars[1]); 1234 if (wp != NULL) 1235 rettv->vval.v_number = wp->w_alist->id; 1236 } 1237 1238 /* 1239 * "argv(nr)" function 1240 */ 1241 static void 1242 f_argv(typval_T *argvars, typval_T *rettv) 1243 { 1244 int idx; 1245 1246 if (argvars[0].v_type != VAR_UNKNOWN) 1247 { 1248 idx = (int)get_tv_number_chk(&argvars[0], NULL); 1249 if (idx >= 0 && idx < ARGCOUNT) 1250 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx])); 1251 else 1252 rettv->vval.v_string = NULL; 1253 rettv->v_type = VAR_STRING; 1254 } 1255 else if (rettv_list_alloc(rettv) == OK) 1256 for (idx = 0; idx < ARGCOUNT; ++idx) 1257 list_append_string(rettv->vval.v_list, 1258 alist_name(&ARGLIST[idx]), -1); 1259 } 1260 1261 /* 1262 * "assert_equal(expected, actual[, msg])" function 1263 */ 1264 static void 1265 f_assert_equal(typval_T *argvars, typval_T *rettv UNUSED) 1266 { 1267 assert_equal_common(argvars, ASSERT_EQUAL); 1268 } 1269 1270 /* 1271 * "assert_notequal(expected, actual[, msg])" function 1272 */ 1273 static void 1274 f_assert_notequal(typval_T *argvars, typval_T *rettv UNUSED) 1275 { 1276 assert_equal_common(argvars, ASSERT_NOTEQUAL); 1277 } 1278 1279 /* 1280 * "assert_exception(string[, msg])" function 1281 */ 1282 static void 1283 f_assert_exception(typval_T *argvars, typval_T *rettv UNUSED) 1284 { 1285 assert_exception(argvars); 1286 } 1287 1288 /* 1289 * "assert_fails(cmd [, error])" function 1290 */ 1291 static void 1292 f_assert_fails(typval_T *argvars, typval_T *rettv UNUSED) 1293 { 1294 assert_fails(argvars); 1295 } 1296 1297 /* 1298 * "assert_false(actual[, msg])" function 1299 */ 1300 static void 1301 f_assert_false(typval_T *argvars, typval_T *rettv UNUSED) 1302 { 1303 assert_bool(argvars, FALSE); 1304 } 1305 1306 /* 1307 * "assert_inrange(lower, upper[, msg])" function 1308 */ 1309 static void 1310 f_assert_inrange(typval_T *argvars, typval_T *rettv UNUSED) 1311 { 1312 assert_inrange(argvars); 1313 } 1314 1315 /* 1316 * "assert_match(pattern, actual[, msg])" function 1317 */ 1318 static void 1319 f_assert_match(typval_T *argvars, typval_T *rettv UNUSED) 1320 { 1321 assert_match_common(argvars, ASSERT_MATCH); 1322 } 1323 1324 /* 1325 * "assert_notmatch(pattern, actual[, msg])" function 1326 */ 1327 static void 1328 f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED) 1329 { 1330 assert_match_common(argvars, ASSERT_NOTMATCH); 1331 } 1332 1333 /* 1334 * "assert_report(msg)" function 1335 */ 1336 static void 1337 f_assert_report(typval_T *argvars, typval_T *rettv UNUSED) 1338 { 1339 assert_report(argvars); 1340 } 1341 1342 /* 1343 * "assert_true(actual[, msg])" function 1344 */ 1345 static void 1346 f_assert_true(typval_T *argvars, typval_T *rettv UNUSED) 1347 { 1348 assert_bool(argvars, TRUE); 1349 } 1350 1351 #ifdef FEAT_FLOAT 1352 /* 1353 * "asin()" function 1354 */ 1355 static void 1356 f_asin(typval_T *argvars, typval_T *rettv) 1357 { 1358 float_T f = 0.0; 1359 1360 rettv->v_type = VAR_FLOAT; 1361 if (get_float_arg(argvars, &f) == OK) 1362 rettv->vval.v_float = asin(f); 1363 else 1364 rettv->vval.v_float = 0.0; 1365 } 1366 1367 /* 1368 * "atan()" function 1369 */ 1370 static void 1371 f_atan(typval_T *argvars, typval_T *rettv) 1372 { 1373 float_T f = 0.0; 1374 1375 rettv->v_type = VAR_FLOAT; 1376 if (get_float_arg(argvars, &f) == OK) 1377 rettv->vval.v_float = atan(f); 1378 else 1379 rettv->vval.v_float = 0.0; 1380 } 1381 1382 /* 1383 * "atan2()" function 1384 */ 1385 static void 1386 f_atan2(typval_T *argvars, typval_T *rettv) 1387 { 1388 float_T fx = 0.0, fy = 0.0; 1389 1390 rettv->v_type = VAR_FLOAT; 1391 if (get_float_arg(argvars, &fx) == OK 1392 && get_float_arg(&argvars[1], &fy) == OK) 1393 rettv->vval.v_float = atan2(fx, fy); 1394 else 1395 rettv->vval.v_float = 0.0; 1396 } 1397 #endif 1398 1399 /* 1400 * "balloon_show()" function 1401 */ 1402 #ifdef FEAT_BEVAL 1403 static void 1404 f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED) 1405 { 1406 if (balloonEval != NULL) 1407 gui_mch_post_balloon(balloonEval, get_tv_string_chk(&argvars[0])); 1408 } 1409 #endif 1410 1411 /* 1412 * "browse(save, title, initdir, default)" function 1413 */ 1414 static void 1415 f_browse(typval_T *argvars UNUSED, typval_T *rettv) 1416 { 1417 #ifdef FEAT_BROWSE 1418 int save; 1419 char_u *title; 1420 char_u *initdir; 1421 char_u *defname; 1422 char_u buf[NUMBUFLEN]; 1423 char_u buf2[NUMBUFLEN]; 1424 int error = FALSE; 1425 1426 save = (int)get_tv_number_chk(&argvars[0], &error); 1427 title = get_tv_string_chk(&argvars[1]); 1428 initdir = get_tv_string_buf_chk(&argvars[2], buf); 1429 defname = get_tv_string_buf_chk(&argvars[3], buf2); 1430 1431 if (error || title == NULL || initdir == NULL || defname == NULL) 1432 rettv->vval.v_string = NULL; 1433 else 1434 rettv->vval.v_string = 1435 do_browse(save ? BROWSE_SAVE : 0, 1436 title, defname, NULL, initdir, NULL, curbuf); 1437 #else 1438 rettv->vval.v_string = NULL; 1439 #endif 1440 rettv->v_type = VAR_STRING; 1441 } 1442 1443 /* 1444 * "browsedir(title, initdir)" function 1445 */ 1446 static void 1447 f_browsedir(typval_T *argvars UNUSED, typval_T *rettv) 1448 { 1449 #ifdef FEAT_BROWSE 1450 char_u *title; 1451 char_u *initdir; 1452 char_u buf[NUMBUFLEN]; 1453 1454 title = get_tv_string_chk(&argvars[0]); 1455 initdir = get_tv_string_buf_chk(&argvars[1], buf); 1456 1457 if (title == NULL || initdir == NULL) 1458 rettv->vval.v_string = NULL; 1459 else 1460 rettv->vval.v_string = do_browse(BROWSE_DIR, 1461 title, NULL, NULL, initdir, NULL, curbuf); 1462 #else 1463 rettv->vval.v_string = NULL; 1464 #endif 1465 rettv->v_type = VAR_STRING; 1466 } 1467 1468 static buf_T *find_buffer(typval_T *avar); 1469 1470 /* 1471 * Find a buffer by number or exact name. 1472 */ 1473 static buf_T * 1474 find_buffer(typval_T *avar) 1475 { 1476 buf_T *buf = NULL; 1477 1478 if (avar->v_type == VAR_NUMBER) 1479 buf = buflist_findnr((int)avar->vval.v_number); 1480 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) 1481 { 1482 buf = buflist_findname_exp(avar->vval.v_string); 1483 if (buf == NULL) 1484 { 1485 /* No full path name match, try a match with a URL or a "nofile" 1486 * buffer, these don't use the full path. */ 1487 FOR_ALL_BUFFERS(buf) 1488 if (buf->b_fname != NULL 1489 && (path_with_url(buf->b_fname) 1490 #ifdef FEAT_QUICKFIX 1491 || bt_nofile(buf) 1492 #endif 1493 ) 1494 && STRCMP(buf->b_fname, avar->vval.v_string) == 0) 1495 break; 1496 } 1497 } 1498 return buf; 1499 } 1500 1501 /* 1502 * "bufexists(expr)" function 1503 */ 1504 static void 1505 f_bufexists(typval_T *argvars, typval_T *rettv) 1506 { 1507 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL); 1508 } 1509 1510 /* 1511 * "buflisted(expr)" function 1512 */ 1513 static void 1514 f_buflisted(typval_T *argvars, typval_T *rettv) 1515 { 1516 buf_T *buf; 1517 1518 buf = find_buffer(&argvars[0]); 1519 rettv->vval.v_number = (buf != NULL && buf->b_p_bl); 1520 } 1521 1522 /* 1523 * "bufloaded(expr)" function 1524 */ 1525 static void 1526 f_bufloaded(typval_T *argvars, typval_T *rettv) 1527 { 1528 buf_T *buf; 1529 1530 buf = find_buffer(&argvars[0]); 1531 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL); 1532 } 1533 1534 buf_T * 1535 buflist_find_by_name(char_u *name, int curtab_only) 1536 { 1537 int save_magic; 1538 char_u *save_cpo; 1539 buf_T *buf; 1540 1541 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */ 1542 save_magic = p_magic; 1543 p_magic = TRUE; 1544 save_cpo = p_cpo; 1545 p_cpo = (char_u *)""; 1546 1547 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name), 1548 TRUE, FALSE, curtab_only)); 1549 1550 p_magic = save_magic; 1551 p_cpo = save_cpo; 1552 return buf; 1553 } 1554 1555 /* 1556 * Get buffer by number or pattern. 1557 */ 1558 buf_T * 1559 get_buf_tv(typval_T *tv, int curtab_only) 1560 { 1561 char_u *name = tv->vval.v_string; 1562 buf_T *buf; 1563 1564 if (tv->v_type == VAR_NUMBER) 1565 return buflist_findnr((int)tv->vval.v_number); 1566 if (tv->v_type != VAR_STRING) 1567 return NULL; 1568 if (name == NULL || *name == NUL) 1569 return curbuf; 1570 if (name[0] == '$' && name[1] == NUL) 1571 return lastbuf; 1572 1573 buf = buflist_find_by_name(name, curtab_only); 1574 1575 /* If not found, try expanding the name, like done for bufexists(). */ 1576 if (buf == NULL) 1577 buf = find_buffer(tv); 1578 1579 return buf; 1580 } 1581 1582 /* 1583 * "bufname(expr)" function 1584 */ 1585 static void 1586 f_bufname(typval_T *argvars, typval_T *rettv) 1587 { 1588 buf_T *buf; 1589 1590 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ 1591 ++emsg_off; 1592 buf = get_buf_tv(&argvars[0], FALSE); 1593 rettv->v_type = VAR_STRING; 1594 if (buf != NULL && buf->b_fname != NULL) 1595 rettv->vval.v_string = vim_strsave(buf->b_fname); 1596 else 1597 rettv->vval.v_string = NULL; 1598 --emsg_off; 1599 } 1600 1601 /* 1602 * "bufnr(expr)" function 1603 */ 1604 static void 1605 f_bufnr(typval_T *argvars, typval_T *rettv) 1606 { 1607 buf_T *buf; 1608 int error = FALSE; 1609 char_u *name; 1610 1611 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ 1612 ++emsg_off; 1613 buf = get_buf_tv(&argvars[0], FALSE); 1614 --emsg_off; 1615 1616 /* If the buffer isn't found and the second argument is not zero create a 1617 * new buffer. */ 1618 if (buf == NULL 1619 && argvars[1].v_type != VAR_UNKNOWN 1620 && get_tv_number_chk(&argvars[1], &error) != 0 1621 && !error 1622 && (name = get_tv_string_chk(&argvars[0])) != NULL 1623 && !error) 1624 buf = buflist_new(name, NULL, (linenr_T)1, 0); 1625 1626 if (buf != NULL) 1627 rettv->vval.v_number = buf->b_fnum; 1628 else 1629 rettv->vval.v_number = -1; 1630 } 1631 1632 static void 1633 buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr) 1634 { 1635 #ifdef FEAT_WINDOWS 1636 win_T *wp; 1637 int winnr = 0; 1638 #endif 1639 buf_T *buf; 1640 1641 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ 1642 ++emsg_off; 1643 buf = get_buf_tv(&argvars[0], TRUE); 1644 #ifdef FEAT_WINDOWS 1645 FOR_ALL_WINDOWS(wp) 1646 { 1647 ++winnr; 1648 if (wp->w_buffer == buf) 1649 break; 1650 } 1651 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1); 1652 #else 1653 rettv->vval.v_number = (curwin->w_buffer == buf 1654 ? (get_nr ? 1 : curwin->w_id) : -1); 1655 #endif 1656 --emsg_off; 1657 } 1658 1659 /* 1660 * "bufwinid(nr)" function 1661 */ 1662 static void 1663 f_bufwinid(typval_T *argvars, typval_T *rettv) 1664 { 1665 buf_win_common(argvars, rettv, FALSE); 1666 } 1667 1668 /* 1669 * "bufwinnr(nr)" function 1670 */ 1671 static void 1672 f_bufwinnr(typval_T *argvars, typval_T *rettv) 1673 { 1674 buf_win_common(argvars, rettv, TRUE); 1675 } 1676 1677 /* 1678 * "byte2line(byte)" function 1679 */ 1680 static void 1681 f_byte2line(typval_T *argvars UNUSED, typval_T *rettv) 1682 { 1683 #ifndef FEAT_BYTEOFF 1684 rettv->vval.v_number = -1; 1685 #else 1686 long boff = 0; 1687 1688 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */ 1689 if (boff < 0) 1690 rettv->vval.v_number = -1; 1691 else 1692 rettv->vval.v_number = ml_find_line_or_offset(curbuf, 1693 (linenr_T)0, &boff); 1694 #endif 1695 } 1696 1697 static void 1698 byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED) 1699 { 1700 #ifdef FEAT_MBYTE 1701 char_u *t; 1702 #endif 1703 char_u *str; 1704 varnumber_T idx; 1705 1706 str = get_tv_string_chk(&argvars[0]); 1707 idx = get_tv_number_chk(&argvars[1], NULL); 1708 rettv->vval.v_number = -1; 1709 if (str == NULL || idx < 0) 1710 return; 1711 1712 #ifdef FEAT_MBYTE 1713 t = str; 1714 for ( ; idx > 0; idx--) 1715 { 1716 if (*t == NUL) /* EOL reached */ 1717 return; 1718 if (enc_utf8 && comp) 1719 t += utf_ptr2len(t); 1720 else 1721 t += (*mb_ptr2len)(t); 1722 } 1723 rettv->vval.v_number = (varnumber_T)(t - str); 1724 #else 1725 if ((size_t)idx <= STRLEN(str)) 1726 rettv->vval.v_number = idx; 1727 #endif 1728 } 1729 1730 /* 1731 * "byteidx()" function 1732 */ 1733 static void 1734 f_byteidx(typval_T *argvars, typval_T *rettv) 1735 { 1736 byteidx(argvars, rettv, FALSE); 1737 } 1738 1739 /* 1740 * "byteidxcomp()" function 1741 */ 1742 static void 1743 f_byteidxcomp(typval_T *argvars, typval_T *rettv) 1744 { 1745 byteidx(argvars, rettv, TRUE); 1746 } 1747 1748 /* 1749 * "call(func, arglist [, dict])" function 1750 */ 1751 static void 1752 f_call(typval_T *argvars, typval_T *rettv) 1753 { 1754 char_u *func; 1755 partial_T *partial = NULL; 1756 dict_T *selfdict = NULL; 1757 1758 if (argvars[1].v_type != VAR_LIST) 1759 { 1760 EMSG(_(e_listreq)); 1761 return; 1762 } 1763 if (argvars[1].vval.v_list == NULL) 1764 return; 1765 1766 if (argvars[0].v_type == VAR_FUNC) 1767 func = argvars[0].vval.v_string; 1768 else if (argvars[0].v_type == VAR_PARTIAL) 1769 { 1770 partial = argvars[0].vval.v_partial; 1771 func = partial_name(partial); 1772 } 1773 else 1774 func = get_tv_string(&argvars[0]); 1775 if (*func == NUL) 1776 return; /* type error or empty name */ 1777 1778 if (argvars[2].v_type != VAR_UNKNOWN) 1779 { 1780 if (argvars[2].v_type != VAR_DICT) 1781 { 1782 EMSG(_(e_dictreq)); 1783 return; 1784 } 1785 selfdict = argvars[2].vval.v_dict; 1786 } 1787 1788 (void)func_call(func, &argvars[1], partial, selfdict, rettv); 1789 } 1790 1791 #ifdef FEAT_FLOAT 1792 /* 1793 * "ceil({float})" function 1794 */ 1795 static void 1796 f_ceil(typval_T *argvars, typval_T *rettv) 1797 { 1798 float_T f = 0.0; 1799 1800 rettv->v_type = VAR_FLOAT; 1801 if (get_float_arg(argvars, &f) == OK) 1802 rettv->vval.v_float = ceil(f); 1803 else 1804 rettv->vval.v_float = 0.0; 1805 } 1806 #endif 1807 1808 #ifdef FEAT_JOB_CHANNEL 1809 /* 1810 * "ch_canread()" function 1811 */ 1812 static void 1813 f_ch_canread(typval_T *argvars, typval_T *rettv) 1814 { 1815 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); 1816 1817 rettv->vval.v_number = 0; 1818 if (channel != NULL) 1819 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK) 1820 || channel_has_readahead(channel, PART_OUT) 1821 || channel_has_readahead(channel, PART_ERR); 1822 } 1823 1824 /* 1825 * "ch_close()" function 1826 */ 1827 static void 1828 f_ch_close(typval_T *argvars, typval_T *rettv UNUSED) 1829 { 1830 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); 1831 1832 if (channel != NULL) 1833 { 1834 channel_close(channel, FALSE); 1835 channel_clear(channel); 1836 } 1837 } 1838 1839 /* 1840 * "ch_close()" function 1841 */ 1842 static void 1843 f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED) 1844 { 1845 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); 1846 1847 if (channel != NULL) 1848 channel_close_in(channel); 1849 } 1850 1851 /* 1852 * "ch_getbufnr()" function 1853 */ 1854 static void 1855 f_ch_getbufnr(typval_T *argvars, typval_T *rettv) 1856 { 1857 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); 1858 1859 rettv->vval.v_number = -1; 1860 if (channel != NULL) 1861 { 1862 char_u *what = get_tv_string(&argvars[1]); 1863 int part; 1864 1865 if (STRCMP(what, "err") == 0) 1866 part = PART_ERR; 1867 else if (STRCMP(what, "out") == 0) 1868 part = PART_OUT; 1869 else if (STRCMP(what, "in") == 0) 1870 part = PART_IN; 1871 else 1872 part = PART_SOCK; 1873 if (channel->ch_part[part].ch_bufref.br_buf != NULL) 1874 rettv->vval.v_number = 1875 channel->ch_part[part].ch_bufref.br_buf->b_fnum; 1876 } 1877 } 1878 1879 /* 1880 * "ch_getjob()" function 1881 */ 1882 static void 1883 f_ch_getjob(typval_T *argvars, typval_T *rettv) 1884 { 1885 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); 1886 1887 if (channel != NULL) 1888 { 1889 rettv->v_type = VAR_JOB; 1890 rettv->vval.v_job = channel->ch_job; 1891 if (channel->ch_job != NULL) 1892 ++channel->ch_job->jv_refcount; 1893 } 1894 } 1895 1896 /* 1897 * "ch_info()" function 1898 */ 1899 static void 1900 f_ch_info(typval_T *argvars, typval_T *rettv UNUSED) 1901 { 1902 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); 1903 1904 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL) 1905 channel_info(channel, rettv->vval.v_dict); 1906 } 1907 1908 /* 1909 * "ch_log()" function 1910 */ 1911 static void 1912 f_ch_log(typval_T *argvars, typval_T *rettv UNUSED) 1913 { 1914 char_u *msg = get_tv_string(&argvars[0]); 1915 channel_T *channel = NULL; 1916 1917 if (argvars[1].v_type != VAR_UNKNOWN) 1918 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0); 1919 1920 ch_log(channel, (char *)msg); 1921 } 1922 1923 /* 1924 * "ch_logfile()" function 1925 */ 1926 static void 1927 f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED) 1928 { 1929 char_u *fname; 1930 char_u *opt = (char_u *)""; 1931 char_u buf[NUMBUFLEN]; 1932 1933 fname = get_tv_string(&argvars[0]); 1934 if (argvars[1].v_type == VAR_STRING) 1935 opt = get_tv_string_buf(&argvars[1], buf); 1936 ch_logfile(fname, opt); 1937 } 1938 1939 /* 1940 * "ch_open()" function 1941 */ 1942 static void 1943 f_ch_open(typval_T *argvars, typval_T *rettv) 1944 { 1945 rettv->v_type = VAR_CHANNEL; 1946 if (check_restricted() || check_secure()) 1947 return; 1948 rettv->vval.v_channel = channel_open_func(argvars); 1949 } 1950 1951 /* 1952 * "ch_read()" function 1953 */ 1954 static void 1955 f_ch_read(typval_T *argvars, typval_T *rettv) 1956 { 1957 common_channel_read(argvars, rettv, FALSE); 1958 } 1959 1960 /* 1961 * "ch_readraw()" function 1962 */ 1963 static void 1964 f_ch_readraw(typval_T *argvars, typval_T *rettv) 1965 { 1966 common_channel_read(argvars, rettv, TRUE); 1967 } 1968 1969 /* 1970 * "ch_evalexpr()" function 1971 */ 1972 static void 1973 f_ch_evalexpr(typval_T *argvars, typval_T *rettv) 1974 { 1975 ch_expr_common(argvars, rettv, TRUE); 1976 } 1977 1978 /* 1979 * "ch_sendexpr()" function 1980 */ 1981 static void 1982 f_ch_sendexpr(typval_T *argvars, typval_T *rettv) 1983 { 1984 ch_expr_common(argvars, rettv, FALSE); 1985 } 1986 1987 /* 1988 * "ch_evalraw()" function 1989 */ 1990 static void 1991 f_ch_evalraw(typval_T *argvars, typval_T *rettv) 1992 { 1993 ch_raw_common(argvars, rettv, TRUE); 1994 } 1995 1996 /* 1997 * "ch_sendraw()" function 1998 */ 1999 static void 2000 f_ch_sendraw(typval_T *argvars, typval_T *rettv) 2001 { 2002 ch_raw_common(argvars, rettv, FALSE); 2003 } 2004 2005 /* 2006 * "ch_setoptions()" function 2007 */ 2008 static void 2009 f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED) 2010 { 2011 channel_T *channel; 2012 jobopt_T opt; 2013 2014 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); 2015 if (channel == NULL) 2016 return; 2017 clear_job_options(&opt); 2018 if (get_job_options(&argvars[1], &opt, 2019 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL) == OK) 2020 channel_set_options(channel, &opt); 2021 free_job_options(&opt); 2022 } 2023 2024 /* 2025 * "ch_status()" function 2026 */ 2027 static void 2028 f_ch_status(typval_T *argvars, typval_T *rettv) 2029 { 2030 channel_T *channel; 2031 jobopt_T opt; 2032 int part = -1; 2033 2034 /* return an empty string by default */ 2035 rettv->v_type = VAR_STRING; 2036 rettv->vval.v_string = NULL; 2037 2038 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); 2039 2040 if (argvars[1].v_type != VAR_UNKNOWN) 2041 { 2042 clear_job_options(&opt); 2043 if (get_job_options(&argvars[1], &opt, JO_PART) == OK 2044 && (opt.jo_set & JO_PART)) 2045 part = opt.jo_part; 2046 } 2047 2048 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part)); 2049 } 2050 #endif 2051 2052 /* 2053 * "changenr()" function 2054 */ 2055 static void 2056 f_changenr(typval_T *argvars UNUSED, typval_T *rettv) 2057 { 2058 rettv->vval.v_number = curbuf->b_u_seq_cur; 2059 } 2060 2061 /* 2062 * "char2nr(string)" function 2063 */ 2064 static void 2065 f_char2nr(typval_T *argvars, typval_T *rettv) 2066 { 2067 #ifdef FEAT_MBYTE 2068 if (has_mbyte) 2069 { 2070 int utf8 = 0; 2071 2072 if (argvars[1].v_type != VAR_UNKNOWN) 2073 utf8 = (int)get_tv_number_chk(&argvars[1], NULL); 2074 2075 if (utf8) 2076 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0])); 2077 else 2078 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0])); 2079 } 2080 else 2081 #endif 2082 rettv->vval.v_number = get_tv_string(&argvars[0])[0]; 2083 } 2084 2085 /* 2086 * "cindent(lnum)" function 2087 */ 2088 static void 2089 f_cindent(typval_T *argvars UNUSED, typval_T *rettv) 2090 { 2091 #ifdef FEAT_CINDENT 2092 pos_T pos; 2093 linenr_T lnum; 2094 2095 pos = curwin->w_cursor; 2096 lnum = get_tv_lnum(argvars); 2097 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) 2098 { 2099 curwin->w_cursor.lnum = lnum; 2100 rettv->vval.v_number = get_c_indent(); 2101 curwin->w_cursor = pos; 2102 } 2103 else 2104 #endif 2105 rettv->vval.v_number = -1; 2106 } 2107 2108 /* 2109 * "clearmatches()" function 2110 */ 2111 static void 2112 f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 2113 { 2114 #ifdef FEAT_SEARCH_EXTRA 2115 clear_matches(curwin); 2116 #endif 2117 } 2118 2119 /* 2120 * "col(string)" function 2121 */ 2122 static void 2123 f_col(typval_T *argvars, typval_T *rettv) 2124 { 2125 colnr_T col = 0; 2126 pos_T *fp; 2127 int fnum = curbuf->b_fnum; 2128 2129 fp = var2fpos(&argvars[0], FALSE, &fnum); 2130 if (fp != NULL && fnum == curbuf->b_fnum) 2131 { 2132 if (fp->col == MAXCOL) 2133 { 2134 /* '> can be MAXCOL, get the length of the line then */ 2135 if (fp->lnum <= curbuf->b_ml.ml_line_count) 2136 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1; 2137 else 2138 col = MAXCOL; 2139 } 2140 else 2141 { 2142 col = fp->col + 1; 2143 #ifdef FEAT_VIRTUALEDIT 2144 /* col(".") when the cursor is on the NUL at the end of the line 2145 * because of "coladd" can be seen as an extra column. */ 2146 if (virtual_active() && fp == &curwin->w_cursor) 2147 { 2148 char_u *p = ml_get_cursor(); 2149 2150 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p, 2151 curwin->w_virtcol - curwin->w_cursor.coladd)) 2152 { 2153 # ifdef FEAT_MBYTE 2154 int l; 2155 2156 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL) 2157 col += l; 2158 # else 2159 if (*p != NUL && p[1] == NUL) 2160 ++col; 2161 # endif 2162 } 2163 } 2164 #endif 2165 } 2166 } 2167 rettv->vval.v_number = col; 2168 } 2169 2170 #if defined(FEAT_INS_EXPAND) 2171 /* 2172 * "complete()" function 2173 */ 2174 static void 2175 f_complete(typval_T *argvars, typval_T *rettv UNUSED) 2176 { 2177 int startcol; 2178 2179 if ((State & INSERT) == 0) 2180 { 2181 EMSG(_("E785: complete() can only be used in Insert mode")); 2182 return; 2183 } 2184 2185 /* Check for undo allowed here, because if something was already inserted 2186 * the line was already saved for undo and this check isn't done. */ 2187 if (!undo_allowed()) 2188 return; 2189 2190 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL) 2191 { 2192 EMSG(_(e_invarg)); 2193 return; 2194 } 2195 2196 startcol = (int)get_tv_number_chk(&argvars[0], NULL); 2197 if (startcol <= 0) 2198 return; 2199 2200 set_completion(startcol - 1, argvars[1].vval.v_list); 2201 } 2202 2203 /* 2204 * "complete_add()" function 2205 */ 2206 static void 2207 f_complete_add(typval_T *argvars, typval_T *rettv) 2208 { 2209 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0); 2210 } 2211 2212 /* 2213 * "complete_check()" function 2214 */ 2215 static void 2216 f_complete_check(typval_T *argvars UNUSED, typval_T *rettv) 2217 { 2218 int saved = RedrawingDisabled; 2219 2220 RedrawingDisabled = 0; 2221 ins_compl_check_keys(0, TRUE); 2222 rettv->vval.v_number = compl_interrupted; 2223 RedrawingDisabled = saved; 2224 } 2225 #endif 2226 2227 /* 2228 * "confirm(message, buttons[, default [, type]])" function 2229 */ 2230 static void 2231 f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 2232 { 2233 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 2234 char_u *message; 2235 char_u *buttons = NULL; 2236 char_u buf[NUMBUFLEN]; 2237 char_u buf2[NUMBUFLEN]; 2238 int def = 1; 2239 int type = VIM_GENERIC; 2240 char_u *typestr; 2241 int error = FALSE; 2242 2243 message = get_tv_string_chk(&argvars[0]); 2244 if (message == NULL) 2245 error = TRUE; 2246 if (argvars[1].v_type != VAR_UNKNOWN) 2247 { 2248 buttons = get_tv_string_buf_chk(&argvars[1], buf); 2249 if (buttons == NULL) 2250 error = TRUE; 2251 if (argvars[2].v_type != VAR_UNKNOWN) 2252 { 2253 def = (int)get_tv_number_chk(&argvars[2], &error); 2254 if (argvars[3].v_type != VAR_UNKNOWN) 2255 { 2256 typestr = get_tv_string_buf_chk(&argvars[3], buf2); 2257 if (typestr == NULL) 2258 error = TRUE; 2259 else 2260 { 2261 switch (TOUPPER_ASC(*typestr)) 2262 { 2263 case 'E': type = VIM_ERROR; break; 2264 case 'Q': type = VIM_QUESTION; break; 2265 case 'I': type = VIM_INFO; break; 2266 case 'W': type = VIM_WARNING; break; 2267 case 'G': type = VIM_GENERIC; break; 2268 } 2269 } 2270 } 2271 } 2272 } 2273 2274 if (buttons == NULL || *buttons == NUL) 2275 buttons = (char_u *)_("&Ok"); 2276 2277 if (!error) 2278 rettv->vval.v_number = do_dialog(type, NULL, message, buttons, 2279 def, NULL, FALSE); 2280 #endif 2281 } 2282 2283 /* 2284 * "copy()" function 2285 */ 2286 static void 2287 f_copy(typval_T *argvars, typval_T *rettv) 2288 { 2289 item_copy(&argvars[0], rettv, FALSE, 0); 2290 } 2291 2292 #ifdef FEAT_FLOAT 2293 /* 2294 * "cos()" function 2295 */ 2296 static void 2297 f_cos(typval_T *argvars, typval_T *rettv) 2298 { 2299 float_T f = 0.0; 2300 2301 rettv->v_type = VAR_FLOAT; 2302 if (get_float_arg(argvars, &f) == OK) 2303 rettv->vval.v_float = cos(f); 2304 else 2305 rettv->vval.v_float = 0.0; 2306 } 2307 2308 /* 2309 * "cosh()" function 2310 */ 2311 static void 2312 f_cosh(typval_T *argvars, typval_T *rettv) 2313 { 2314 float_T f = 0.0; 2315 2316 rettv->v_type = VAR_FLOAT; 2317 if (get_float_arg(argvars, &f) == OK) 2318 rettv->vval.v_float = cosh(f); 2319 else 2320 rettv->vval.v_float = 0.0; 2321 } 2322 #endif 2323 2324 /* 2325 * "count()" function 2326 */ 2327 static void 2328 f_count(typval_T *argvars, typval_T *rettv) 2329 { 2330 long n = 0; 2331 int ic = FALSE; 2332 int error = FALSE; 2333 2334 if (argvars[2].v_type != VAR_UNKNOWN) 2335 ic = (int)get_tv_number_chk(&argvars[2], &error); 2336 2337 if (argvars[0].v_type == VAR_STRING) 2338 { 2339 char_u *expr = get_tv_string_chk(&argvars[1]); 2340 char_u *p = argvars[0].vval.v_string; 2341 char_u *next; 2342 2343 if (!error && expr != NULL && p != NULL) 2344 { 2345 if (ic) 2346 { 2347 size_t len = STRLEN(expr); 2348 2349 while (*p != NUL) 2350 { 2351 if (MB_STRNICMP(p, expr, len) == 0) 2352 { 2353 ++n; 2354 p += len; 2355 } 2356 else 2357 MB_PTR_ADV(p); 2358 } 2359 } 2360 else 2361 while ((next = (char_u *)strstr((char *)p, (char *)expr)) 2362 != NULL) 2363 { 2364 ++n; 2365 p = next + STRLEN(expr); 2366 } 2367 } 2368 2369 } 2370 else if (argvars[0].v_type == VAR_LIST) 2371 { 2372 listitem_T *li; 2373 list_T *l; 2374 long idx; 2375 2376 if ((l = argvars[0].vval.v_list) != NULL) 2377 { 2378 li = l->lv_first; 2379 if (argvars[2].v_type != VAR_UNKNOWN) 2380 { 2381 if (argvars[3].v_type != VAR_UNKNOWN) 2382 { 2383 idx = (long)get_tv_number_chk(&argvars[3], &error); 2384 if (!error) 2385 { 2386 li = list_find(l, idx); 2387 if (li == NULL) 2388 EMSGN(_(e_listidx), idx); 2389 } 2390 } 2391 if (error) 2392 li = NULL; 2393 } 2394 2395 for ( ; li != NULL; li = li->li_next) 2396 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE)) 2397 ++n; 2398 } 2399 } 2400 else if (argvars[0].v_type == VAR_DICT) 2401 { 2402 int todo; 2403 dict_T *d; 2404 hashitem_T *hi; 2405 2406 if ((d = argvars[0].vval.v_dict) != NULL) 2407 { 2408 if (argvars[2].v_type != VAR_UNKNOWN) 2409 { 2410 if (argvars[3].v_type != VAR_UNKNOWN) 2411 EMSG(_(e_invarg)); 2412 } 2413 2414 todo = error ? 0 : (int)d->dv_hashtab.ht_used; 2415 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) 2416 { 2417 if (!HASHITEM_EMPTY(hi)) 2418 { 2419 --todo; 2420 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE)) 2421 ++n; 2422 } 2423 } 2424 } 2425 } 2426 else 2427 EMSG2(_(e_listdictarg), "count()"); 2428 rettv->vval.v_number = n; 2429 } 2430 2431 /* 2432 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function 2433 * 2434 * Checks the existence of a cscope connection. 2435 */ 2436 static void 2437 f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 2438 { 2439 #ifdef FEAT_CSCOPE 2440 int num = 0; 2441 char_u *dbpath = NULL; 2442 char_u *prepend = NULL; 2443 char_u buf[NUMBUFLEN]; 2444 2445 if (argvars[0].v_type != VAR_UNKNOWN 2446 && argvars[1].v_type != VAR_UNKNOWN) 2447 { 2448 num = (int)get_tv_number(&argvars[0]); 2449 dbpath = get_tv_string(&argvars[1]); 2450 if (argvars[2].v_type != VAR_UNKNOWN) 2451 prepend = get_tv_string_buf(&argvars[2], buf); 2452 } 2453 2454 rettv->vval.v_number = cs_connection(num, dbpath, prepend); 2455 #endif 2456 } 2457 2458 /* 2459 * "cursor(lnum, col)" function, or 2460 * "cursor(list)" 2461 * 2462 * Moves the cursor to the specified line and column. 2463 * Returns 0 when the position could be set, -1 otherwise. 2464 */ 2465 static void 2466 f_cursor(typval_T *argvars, typval_T *rettv) 2467 { 2468 long line, col; 2469 #ifdef FEAT_VIRTUALEDIT 2470 long coladd = 0; 2471 #endif 2472 int set_curswant = TRUE; 2473 2474 rettv->vval.v_number = -1; 2475 if (argvars[1].v_type == VAR_UNKNOWN) 2476 { 2477 pos_T pos; 2478 colnr_T curswant = -1; 2479 2480 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL) 2481 { 2482 EMSG(_(e_invarg)); 2483 return; 2484 } 2485 line = pos.lnum; 2486 col = pos.col; 2487 #ifdef FEAT_VIRTUALEDIT 2488 coladd = pos.coladd; 2489 #endif 2490 if (curswant >= 0) 2491 { 2492 curwin->w_curswant = curswant - 1; 2493 set_curswant = FALSE; 2494 } 2495 } 2496 else 2497 { 2498 line = get_tv_lnum(argvars); 2499 col = (long)get_tv_number_chk(&argvars[1], NULL); 2500 #ifdef FEAT_VIRTUALEDIT 2501 if (argvars[2].v_type != VAR_UNKNOWN) 2502 coladd = (long)get_tv_number_chk(&argvars[2], NULL); 2503 #endif 2504 } 2505 if (line < 0 || col < 0 2506 #ifdef FEAT_VIRTUALEDIT 2507 || coladd < 0 2508 #endif 2509 ) 2510 return; /* type error; errmsg already given */ 2511 if (line > 0) 2512 curwin->w_cursor.lnum = line; 2513 if (col > 0) 2514 curwin->w_cursor.col = col - 1; 2515 #ifdef FEAT_VIRTUALEDIT 2516 curwin->w_cursor.coladd = coladd; 2517 #endif 2518 2519 /* Make sure the cursor is in a valid position. */ 2520 check_cursor(); 2521 #ifdef FEAT_MBYTE 2522 /* Correct cursor for multi-byte character. */ 2523 if (has_mbyte) 2524 mb_adjust_cursor(); 2525 #endif 2526 2527 curwin->w_set_curswant = set_curswant; 2528 rettv->vval.v_number = 0; 2529 } 2530 2531 /* 2532 * "deepcopy()" function 2533 */ 2534 static void 2535 f_deepcopy(typval_T *argvars, typval_T *rettv) 2536 { 2537 int noref = 0; 2538 int copyID; 2539 2540 if (argvars[1].v_type != VAR_UNKNOWN) 2541 noref = (int)get_tv_number_chk(&argvars[1], NULL); 2542 if (noref < 0 || noref > 1) 2543 EMSG(_(e_invarg)); 2544 else 2545 { 2546 copyID = get_copyID(); 2547 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0); 2548 } 2549 } 2550 2551 /* 2552 * "delete()" function 2553 */ 2554 static void 2555 f_delete(typval_T *argvars, typval_T *rettv) 2556 { 2557 char_u nbuf[NUMBUFLEN]; 2558 char_u *name; 2559 char_u *flags; 2560 2561 rettv->vval.v_number = -1; 2562 if (check_restricted() || check_secure()) 2563 return; 2564 2565 name = get_tv_string(&argvars[0]); 2566 if (name == NULL || *name == NUL) 2567 { 2568 EMSG(_(e_invarg)); 2569 return; 2570 } 2571 2572 if (argvars[1].v_type != VAR_UNKNOWN) 2573 flags = get_tv_string_buf(&argvars[1], nbuf); 2574 else 2575 flags = (char_u *)""; 2576 2577 if (*flags == NUL) 2578 /* delete a file */ 2579 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1; 2580 else if (STRCMP(flags, "d") == 0) 2581 /* delete an empty directory */ 2582 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1; 2583 else if (STRCMP(flags, "rf") == 0) 2584 /* delete a directory recursively */ 2585 rettv->vval.v_number = delete_recursive(name); 2586 else 2587 EMSG2(_(e_invexpr2), flags); 2588 } 2589 2590 /* 2591 * "did_filetype()" function 2592 */ 2593 static void 2594 f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 2595 { 2596 #ifdef FEAT_AUTOCMD 2597 rettv->vval.v_number = did_filetype; 2598 #endif 2599 } 2600 2601 /* 2602 * "diff_filler()" function 2603 */ 2604 static void 2605 f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 2606 { 2607 #ifdef FEAT_DIFF 2608 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars)); 2609 #endif 2610 } 2611 2612 /* 2613 * "diff_hlID()" function 2614 */ 2615 static void 2616 f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 2617 { 2618 #ifdef FEAT_DIFF 2619 linenr_T lnum = get_tv_lnum(argvars); 2620 static linenr_T prev_lnum = 0; 2621 static varnumber_T changedtick = 0; 2622 static int fnum = 0; 2623 static int change_start = 0; 2624 static int change_end = 0; 2625 static hlf_T hlID = (hlf_T)0; 2626 int filler_lines; 2627 int col; 2628 2629 if (lnum < 0) /* ignore type error in {lnum} arg */ 2630 lnum = 0; 2631 if (lnum != prev_lnum 2632 || changedtick != CHANGEDTICK(curbuf) 2633 || fnum != curbuf->b_fnum) 2634 { 2635 /* New line, buffer, change: need to get the values. */ 2636 filler_lines = diff_check(curwin, lnum); 2637 if (filler_lines < 0) 2638 { 2639 if (filler_lines == -1) 2640 { 2641 change_start = MAXCOL; 2642 change_end = -1; 2643 if (diff_find_change(curwin, lnum, &change_start, &change_end)) 2644 hlID = HLF_ADD; /* added line */ 2645 else 2646 hlID = HLF_CHD; /* changed line */ 2647 } 2648 else 2649 hlID = HLF_ADD; /* added line */ 2650 } 2651 else 2652 hlID = (hlf_T)0; 2653 prev_lnum = lnum; 2654 changedtick = CHANGEDTICK(curbuf); 2655 fnum = curbuf->b_fnum; 2656 } 2657 2658 if (hlID == HLF_CHD || hlID == HLF_TXD) 2659 { 2660 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */ 2661 if (col >= change_start && col <= change_end) 2662 hlID = HLF_TXD; /* changed text */ 2663 else 2664 hlID = HLF_CHD; /* changed line */ 2665 } 2666 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID; 2667 #endif 2668 } 2669 2670 /* 2671 * "empty({expr})" function 2672 */ 2673 static void 2674 f_empty(typval_T *argvars, typval_T *rettv) 2675 { 2676 int n = FALSE; 2677 2678 switch (argvars[0].v_type) 2679 { 2680 case VAR_STRING: 2681 case VAR_FUNC: 2682 n = argvars[0].vval.v_string == NULL 2683 || *argvars[0].vval.v_string == NUL; 2684 break; 2685 case VAR_PARTIAL: 2686 n = FALSE; 2687 break; 2688 case VAR_NUMBER: 2689 n = argvars[0].vval.v_number == 0; 2690 break; 2691 case VAR_FLOAT: 2692 #ifdef FEAT_FLOAT 2693 n = argvars[0].vval.v_float == 0.0; 2694 break; 2695 #endif 2696 case VAR_LIST: 2697 n = argvars[0].vval.v_list == NULL 2698 || argvars[0].vval.v_list->lv_first == NULL; 2699 break; 2700 case VAR_DICT: 2701 n = argvars[0].vval.v_dict == NULL 2702 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0; 2703 break; 2704 case VAR_SPECIAL: 2705 n = argvars[0].vval.v_number != VVAL_TRUE; 2706 break; 2707 2708 case VAR_JOB: 2709 #ifdef FEAT_JOB_CHANNEL 2710 n = argvars[0].vval.v_job == NULL 2711 || argvars[0].vval.v_job->jv_status != JOB_STARTED; 2712 break; 2713 #endif 2714 case VAR_CHANNEL: 2715 #ifdef FEAT_JOB_CHANNEL 2716 n = argvars[0].vval.v_channel == NULL 2717 || !channel_is_open(argvars[0].vval.v_channel); 2718 break; 2719 #endif 2720 case VAR_UNKNOWN: 2721 internal_error("f_empty(UNKNOWN)"); 2722 n = TRUE; 2723 break; 2724 } 2725 2726 rettv->vval.v_number = n; 2727 } 2728 2729 /* 2730 * "escape({string}, {chars})" function 2731 */ 2732 static void 2733 f_escape(typval_T *argvars, typval_T *rettv) 2734 { 2735 char_u buf[NUMBUFLEN]; 2736 2737 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]), 2738 get_tv_string_buf(&argvars[1], buf)); 2739 rettv->v_type = VAR_STRING; 2740 } 2741 2742 /* 2743 * "eval()" function 2744 */ 2745 static void 2746 f_eval(typval_T *argvars, typval_T *rettv) 2747 { 2748 char_u *s, *p; 2749 2750 s = get_tv_string_chk(&argvars[0]); 2751 if (s != NULL) 2752 s = skipwhite(s); 2753 2754 p = s; 2755 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL) 2756 { 2757 if (p != NULL && !aborting()) 2758 EMSG2(_(e_invexpr2), p); 2759 need_clr_eos = FALSE; 2760 rettv->v_type = VAR_NUMBER; 2761 rettv->vval.v_number = 0; 2762 } 2763 else if (*s != NUL) 2764 EMSG(_(e_trailing)); 2765 } 2766 2767 /* 2768 * "eventhandler()" function 2769 */ 2770 static void 2771 f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv) 2772 { 2773 rettv->vval.v_number = vgetc_busy; 2774 } 2775 2776 /* 2777 * "executable()" function 2778 */ 2779 static void 2780 f_executable(typval_T *argvars, typval_T *rettv) 2781 { 2782 char_u *name = get_tv_string(&argvars[0]); 2783 2784 /* Check in $PATH and also check directly if there is a directory name. */ 2785 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE) 2786 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE)); 2787 } 2788 2789 static garray_T redir_execute_ga; 2790 2791 /* 2792 * Append "value[value_len]" to the execute() output. 2793 */ 2794 void 2795 execute_redir_str(char_u *value, int value_len) 2796 { 2797 int len; 2798 2799 if (value_len == -1) 2800 len = (int)STRLEN(value); /* Append the entire string */ 2801 else 2802 len = value_len; /* Append only "value_len" characters */ 2803 if (ga_grow(&redir_execute_ga, len) == OK) 2804 { 2805 mch_memmove((char *)redir_execute_ga.ga_data 2806 + redir_execute_ga.ga_len, value, len); 2807 redir_execute_ga.ga_len += len; 2808 } 2809 } 2810 2811 /* 2812 * Get next line from a list. 2813 * Called by do_cmdline() to get the next line. 2814 * Returns allocated string, or NULL for end of function. 2815 */ 2816 2817 static char_u * 2818 get_list_line( 2819 int c UNUSED, 2820 void *cookie, 2821 int indent UNUSED) 2822 { 2823 listitem_T **p = (listitem_T **)cookie; 2824 listitem_T *item = *p; 2825 char_u buf[NUMBUFLEN]; 2826 char_u *s; 2827 2828 if (item == NULL) 2829 return NULL; 2830 s = get_tv_string_buf_chk(&item->li_tv, buf); 2831 *p = item->li_next; 2832 return s == NULL ? NULL : vim_strsave(s); 2833 } 2834 2835 /* 2836 * "execute()" function 2837 */ 2838 static void 2839 f_execute(typval_T *argvars, typval_T *rettv) 2840 { 2841 char_u *cmd = NULL; 2842 list_T *list = NULL; 2843 int save_msg_silent = msg_silent; 2844 int save_emsg_silent = emsg_silent; 2845 int save_emsg_noredir = emsg_noredir; 2846 int save_redir_execute = redir_execute; 2847 garray_T save_ga; 2848 2849 rettv->vval.v_string = NULL; 2850 rettv->v_type = VAR_STRING; 2851 2852 if (argvars[0].v_type == VAR_LIST) 2853 { 2854 list = argvars[0].vval.v_list; 2855 if (list == NULL || list->lv_first == NULL) 2856 /* empty list, no commands, empty output */ 2857 return; 2858 ++list->lv_refcount; 2859 } 2860 else 2861 { 2862 cmd = get_tv_string_chk(&argvars[0]); 2863 if (cmd == NULL) 2864 return; 2865 } 2866 2867 if (argvars[1].v_type != VAR_UNKNOWN) 2868 { 2869 char_u buf[NUMBUFLEN]; 2870 char_u *s = get_tv_string_buf_chk(&argvars[1], buf); 2871 2872 if (s == NULL) 2873 return; 2874 if (STRNCMP(s, "silent", 6) == 0) 2875 ++msg_silent; 2876 if (STRCMP(s, "silent!") == 0) 2877 { 2878 emsg_silent = TRUE; 2879 emsg_noredir = TRUE; 2880 } 2881 } 2882 else 2883 ++msg_silent; 2884 2885 if (redir_execute) 2886 save_ga = redir_execute_ga; 2887 ga_init2(&redir_execute_ga, (int)sizeof(char), 500); 2888 redir_execute = TRUE; 2889 2890 if (cmd != NULL) 2891 do_cmdline_cmd(cmd); 2892 else 2893 { 2894 listitem_T *item = list->lv_first; 2895 2896 do_cmdline(NULL, get_list_line, (void *)&item, 2897 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED); 2898 --list->lv_refcount; 2899 } 2900 2901 /* Need to append a NUL to the result. */ 2902 if (ga_grow(&redir_execute_ga, 1) == OK) 2903 { 2904 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL; 2905 rettv->vval.v_string = redir_execute_ga.ga_data; 2906 } 2907 else 2908 { 2909 ga_clear(&redir_execute_ga); 2910 rettv->vval.v_string = NULL; 2911 } 2912 msg_silent = save_msg_silent; 2913 emsg_silent = save_emsg_silent; 2914 emsg_noredir = save_emsg_noredir; 2915 2916 redir_execute = save_redir_execute; 2917 if (redir_execute) 2918 redir_execute_ga = save_ga; 2919 2920 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the 2921 * line. Put it back in the first column. */ 2922 msg_col = 0; 2923 } 2924 2925 /* 2926 * "exepath()" function 2927 */ 2928 static void 2929 f_exepath(typval_T *argvars, typval_T *rettv) 2930 { 2931 char_u *p = NULL; 2932 2933 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE); 2934 rettv->v_type = VAR_STRING; 2935 rettv->vval.v_string = p; 2936 } 2937 2938 /* 2939 * "exists()" function 2940 */ 2941 static void 2942 f_exists(typval_T *argvars, typval_T *rettv) 2943 { 2944 char_u *p; 2945 char_u *name; 2946 int n = FALSE; 2947 int len = 0; 2948 2949 p = get_tv_string(&argvars[0]); 2950 if (*p == '$') /* environment variable */ 2951 { 2952 /* first try "normal" environment variables (fast) */ 2953 if (mch_getenv(p + 1) != NULL) 2954 n = TRUE; 2955 else 2956 { 2957 /* try expanding things like $VIM and ${HOME} */ 2958 p = expand_env_save(p); 2959 if (p != NULL && *p != '$') 2960 n = TRUE; 2961 vim_free(p); 2962 } 2963 } 2964 else if (*p == '&' || *p == '+') /* option */ 2965 { 2966 n = (get_option_tv(&p, NULL, TRUE) == OK); 2967 if (*skipwhite(p) != NUL) 2968 n = FALSE; /* trailing garbage */ 2969 } 2970 else if (*p == '*') /* internal or user defined function */ 2971 { 2972 n = function_exists(p + 1, FALSE); 2973 } 2974 else if (*p == ':') 2975 { 2976 n = cmd_exists(p + 1); 2977 } 2978 else if (*p == '#') 2979 { 2980 #ifdef FEAT_AUTOCMD 2981 if (p[1] == '#') 2982 n = autocmd_supported(p + 2); 2983 else 2984 n = au_exists(p + 1); 2985 #endif 2986 } 2987 else /* internal variable */ 2988 { 2989 char_u *tofree; 2990 typval_T tv; 2991 2992 /* get_name_len() takes care of expanding curly braces */ 2993 name = p; 2994 len = get_name_len(&p, &tofree, TRUE, FALSE); 2995 if (len > 0) 2996 { 2997 if (tofree != NULL) 2998 name = tofree; 2999 n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK); 3000 if (n) 3001 { 3002 /* handle d.key, l[idx], f(expr) */ 3003 n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK); 3004 if (n) 3005 clear_tv(&tv); 3006 } 3007 } 3008 if (*p != NUL) 3009 n = FALSE; 3010 3011 vim_free(tofree); 3012 } 3013 3014 rettv->vval.v_number = n; 3015 } 3016 3017 #ifdef FEAT_FLOAT 3018 /* 3019 * "exp()" function 3020 */ 3021 static void 3022 f_exp(typval_T *argvars, typval_T *rettv) 3023 { 3024 float_T f = 0.0; 3025 3026 rettv->v_type = VAR_FLOAT; 3027 if (get_float_arg(argvars, &f) == OK) 3028 rettv->vval.v_float = exp(f); 3029 else 3030 rettv->vval.v_float = 0.0; 3031 } 3032 #endif 3033 3034 /* 3035 * "expand()" function 3036 */ 3037 static void 3038 f_expand(typval_T *argvars, typval_T *rettv) 3039 { 3040 char_u *s; 3041 int len; 3042 char_u *errormsg; 3043 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND; 3044 expand_T xpc; 3045 int error = FALSE; 3046 char_u *result; 3047 3048 rettv->v_type = VAR_STRING; 3049 if (argvars[1].v_type != VAR_UNKNOWN 3050 && argvars[2].v_type != VAR_UNKNOWN 3051 && get_tv_number_chk(&argvars[2], &error) 3052 && !error) 3053 { 3054 rettv_list_set(rettv, NULL); 3055 } 3056 3057 s = get_tv_string(&argvars[0]); 3058 if (*s == '%' || *s == '#' || *s == '<') 3059 { 3060 ++emsg_off; 3061 result = eval_vars(s, s, &len, NULL, &errormsg, NULL); 3062 --emsg_off; 3063 if (rettv->v_type == VAR_LIST) 3064 { 3065 if (rettv_list_alloc(rettv) != FAIL && result != NULL) 3066 list_append_string(rettv->vval.v_list, result, -1); 3067 else 3068 vim_free(result); 3069 } 3070 else 3071 rettv->vval.v_string = result; 3072 } 3073 else 3074 { 3075 /* When the optional second argument is non-zero, don't remove matches 3076 * for 'wildignore' and don't put matches for 'suffixes' at the end. */ 3077 if (argvars[1].v_type != VAR_UNKNOWN 3078 && get_tv_number_chk(&argvars[1], &error)) 3079 options |= WILD_KEEP_ALL; 3080 if (!error) 3081 { 3082 ExpandInit(&xpc); 3083 xpc.xp_context = EXPAND_FILES; 3084 if (p_wic) 3085 options += WILD_ICASE; 3086 if (rettv->v_type == VAR_STRING) 3087 rettv->vval.v_string = ExpandOne(&xpc, s, NULL, 3088 options, WILD_ALL); 3089 else if (rettv_list_alloc(rettv) != FAIL) 3090 { 3091 int i; 3092 3093 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP); 3094 for (i = 0; i < xpc.xp_numfiles; i++) 3095 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); 3096 ExpandCleanup(&xpc); 3097 } 3098 } 3099 else 3100 rettv->vval.v_string = NULL; 3101 } 3102 } 3103 3104 /* 3105 * "extend(list, list [, idx])" function 3106 * "extend(dict, dict [, action])" function 3107 */ 3108 static void 3109 f_extend(typval_T *argvars, typval_T *rettv) 3110 { 3111 char_u *arg_errmsg = (char_u *)N_("extend() argument"); 3112 3113 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) 3114 { 3115 list_T *l1, *l2; 3116 listitem_T *item; 3117 long before; 3118 int error = FALSE; 3119 3120 l1 = argvars[0].vval.v_list; 3121 l2 = argvars[1].vval.v_list; 3122 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE) 3123 && l2 != NULL) 3124 { 3125 if (argvars[2].v_type != VAR_UNKNOWN) 3126 { 3127 before = (long)get_tv_number_chk(&argvars[2], &error); 3128 if (error) 3129 return; /* type error; errmsg already given */ 3130 3131 if (before == l1->lv_len) 3132 item = NULL; 3133 else 3134 { 3135 item = list_find(l1, before); 3136 if (item == NULL) 3137 { 3138 EMSGN(_(e_listidx), before); 3139 return; 3140 } 3141 } 3142 } 3143 else 3144 item = NULL; 3145 list_extend(l1, l2, item); 3146 3147 copy_tv(&argvars[0], rettv); 3148 } 3149 } 3150 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) 3151 { 3152 dict_T *d1, *d2; 3153 char_u *action; 3154 int i; 3155 3156 d1 = argvars[0].vval.v_dict; 3157 d2 = argvars[1].vval.v_dict; 3158 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE) 3159 && d2 != NULL) 3160 { 3161 /* Check the third argument. */ 3162 if (argvars[2].v_type != VAR_UNKNOWN) 3163 { 3164 static char *(av[]) = {"keep", "force", "error"}; 3165 3166 action = get_tv_string_chk(&argvars[2]); 3167 if (action == NULL) 3168 return; /* type error; errmsg already given */ 3169 for (i = 0; i < 3; ++i) 3170 if (STRCMP(action, av[i]) == 0) 3171 break; 3172 if (i == 3) 3173 { 3174 EMSG2(_(e_invarg2), action); 3175 return; 3176 } 3177 } 3178 else 3179 action = (char_u *)"force"; 3180 3181 dict_extend(d1, d2, action); 3182 3183 copy_tv(&argvars[0], rettv); 3184 } 3185 } 3186 else 3187 EMSG2(_(e_listdictarg), "extend()"); 3188 } 3189 3190 /* 3191 * "feedkeys()" function 3192 */ 3193 static void 3194 f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED) 3195 { 3196 int remap = TRUE; 3197 int insert = FALSE; 3198 char_u *keys, *flags; 3199 char_u nbuf[NUMBUFLEN]; 3200 int typed = FALSE; 3201 int execute = FALSE; 3202 int dangerous = FALSE; 3203 char_u *keys_esc; 3204 3205 /* This is not allowed in the sandbox. If the commands would still be 3206 * executed in the sandbox it would be OK, but it probably happens later, 3207 * when "sandbox" is no longer set. */ 3208 if (check_secure()) 3209 return; 3210 3211 keys = get_tv_string(&argvars[0]); 3212 3213 if (argvars[1].v_type != VAR_UNKNOWN) 3214 { 3215 flags = get_tv_string_buf(&argvars[1], nbuf); 3216 for ( ; *flags != NUL; ++flags) 3217 { 3218 switch (*flags) 3219 { 3220 case 'n': remap = FALSE; break; 3221 case 'm': remap = TRUE; break; 3222 case 't': typed = TRUE; break; 3223 case 'i': insert = TRUE; break; 3224 case 'x': execute = TRUE; break; 3225 case '!': dangerous = TRUE; break; 3226 } 3227 } 3228 } 3229 3230 if (*keys != NUL || execute) 3231 { 3232 /* Need to escape K_SPECIAL and CSI before putting the string in the 3233 * typeahead buffer. */ 3234 keys_esc = vim_strsave_escape_csi(keys); 3235 if (keys_esc != NULL) 3236 { 3237 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), 3238 insert ? 0 : typebuf.tb_len, !typed, FALSE); 3239 vim_free(keys_esc); 3240 if (vgetc_busy 3241 #ifdef FEAT_TIMERS 3242 || timer_busy 3243 #endif 3244 ) 3245 typebuf_was_filled = TRUE; 3246 if (execute) 3247 { 3248 int save_msg_scroll = msg_scroll; 3249 3250 /* Avoid a 1 second delay when the keys start Insert mode. */ 3251 msg_scroll = FALSE; 3252 3253 if (!dangerous) 3254 ++ex_normal_busy; 3255 exec_normal(TRUE); 3256 if (!dangerous) 3257 --ex_normal_busy; 3258 msg_scroll |= save_msg_scroll; 3259 } 3260 } 3261 } 3262 } 3263 3264 /* 3265 * "filereadable()" function 3266 */ 3267 static void 3268 f_filereadable(typval_T *argvars, typval_T *rettv) 3269 { 3270 int fd; 3271 char_u *p; 3272 int n; 3273 3274 #ifndef O_NONBLOCK 3275 # define O_NONBLOCK 0 3276 #endif 3277 p = get_tv_string(&argvars[0]); 3278 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p, 3279 O_RDONLY | O_NONBLOCK, 0)) >= 0) 3280 { 3281 n = TRUE; 3282 close(fd); 3283 } 3284 else 3285 n = FALSE; 3286 3287 rettv->vval.v_number = n; 3288 } 3289 3290 /* 3291 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have 3292 * rights to write into. 3293 */ 3294 static void 3295 f_filewritable(typval_T *argvars, typval_T *rettv) 3296 { 3297 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0])); 3298 } 3299 3300 static void 3301 findfilendir( 3302 typval_T *argvars UNUSED, 3303 typval_T *rettv, 3304 int find_what UNUSED) 3305 { 3306 #ifdef FEAT_SEARCHPATH 3307 char_u *fname; 3308 char_u *fresult = NULL; 3309 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; 3310 char_u *p; 3311 char_u pathbuf[NUMBUFLEN]; 3312 int count = 1; 3313 int first = TRUE; 3314 int error = FALSE; 3315 #endif 3316 3317 rettv->vval.v_string = NULL; 3318 rettv->v_type = VAR_STRING; 3319 3320 #ifdef FEAT_SEARCHPATH 3321 fname = get_tv_string(&argvars[0]); 3322 3323 if (argvars[1].v_type != VAR_UNKNOWN) 3324 { 3325 p = get_tv_string_buf_chk(&argvars[1], pathbuf); 3326 if (p == NULL) 3327 error = TRUE; 3328 else 3329 { 3330 if (*p != NUL) 3331 path = p; 3332 3333 if (argvars[2].v_type != VAR_UNKNOWN) 3334 count = (int)get_tv_number_chk(&argvars[2], &error); 3335 } 3336 } 3337 3338 if (count < 0 && rettv_list_alloc(rettv) == FAIL) 3339 error = TRUE; 3340 3341 if (*fname != NUL && !error) 3342 { 3343 do 3344 { 3345 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) 3346 vim_free(fresult); 3347 fresult = find_file_in_path_option(first ? fname : NULL, 3348 first ? (int)STRLEN(fname) : 0, 3349 0, first, path, 3350 find_what, 3351 curbuf->b_ffname, 3352 find_what == FINDFILE_DIR 3353 ? (char_u *)"" : curbuf->b_p_sua); 3354 first = FALSE; 3355 3356 if (fresult != NULL && rettv->v_type == VAR_LIST) 3357 list_append_string(rettv->vval.v_list, fresult, -1); 3358 3359 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL); 3360 } 3361 3362 if (rettv->v_type == VAR_STRING) 3363 rettv->vval.v_string = fresult; 3364 #endif 3365 } 3366 3367 /* 3368 * "filter()" function 3369 */ 3370 static void 3371 f_filter(typval_T *argvars, typval_T *rettv) 3372 { 3373 filter_map(argvars, rettv, FALSE); 3374 } 3375 3376 /* 3377 * "finddir({fname}[, {path}[, {count}]])" function 3378 */ 3379 static void 3380 f_finddir(typval_T *argvars, typval_T *rettv) 3381 { 3382 findfilendir(argvars, rettv, FINDFILE_DIR); 3383 } 3384 3385 /* 3386 * "findfile({fname}[, {path}[, {count}]])" function 3387 */ 3388 static void 3389 f_findfile(typval_T *argvars, typval_T *rettv) 3390 { 3391 findfilendir(argvars, rettv, FINDFILE_FILE); 3392 } 3393 3394 #ifdef FEAT_FLOAT 3395 /* 3396 * "float2nr({float})" function 3397 */ 3398 static void 3399 f_float2nr(typval_T *argvars, typval_T *rettv) 3400 { 3401 float_T f = 0.0; 3402 3403 if (get_float_arg(argvars, &f) == OK) 3404 { 3405 if (f <= -VARNUM_MAX + DBL_EPSILON) 3406 rettv->vval.v_number = -VARNUM_MAX; 3407 else if (f >= VARNUM_MAX - DBL_EPSILON) 3408 rettv->vval.v_number = VARNUM_MAX; 3409 else 3410 rettv->vval.v_number = (varnumber_T)f; 3411 } 3412 } 3413 3414 /* 3415 * "floor({float})" function 3416 */ 3417 static void 3418 f_floor(typval_T *argvars, typval_T *rettv) 3419 { 3420 float_T f = 0.0; 3421 3422 rettv->v_type = VAR_FLOAT; 3423 if (get_float_arg(argvars, &f) == OK) 3424 rettv->vval.v_float = floor(f); 3425 else 3426 rettv->vval.v_float = 0.0; 3427 } 3428 3429 /* 3430 * "fmod()" function 3431 */ 3432 static void 3433 f_fmod(typval_T *argvars, typval_T *rettv) 3434 { 3435 float_T fx = 0.0, fy = 0.0; 3436 3437 rettv->v_type = VAR_FLOAT; 3438 if (get_float_arg(argvars, &fx) == OK 3439 && get_float_arg(&argvars[1], &fy) == OK) 3440 rettv->vval.v_float = fmod(fx, fy); 3441 else 3442 rettv->vval.v_float = 0.0; 3443 } 3444 #endif 3445 3446 /* 3447 * "fnameescape({string})" function 3448 */ 3449 static void 3450 f_fnameescape(typval_T *argvars, typval_T *rettv) 3451 { 3452 rettv->vval.v_string = vim_strsave_fnameescape( 3453 get_tv_string(&argvars[0]), FALSE); 3454 rettv->v_type = VAR_STRING; 3455 } 3456 3457 /* 3458 * "fnamemodify({fname}, {mods})" function 3459 */ 3460 static void 3461 f_fnamemodify(typval_T *argvars, typval_T *rettv) 3462 { 3463 char_u *fname; 3464 char_u *mods; 3465 int usedlen = 0; 3466 int len; 3467 char_u *fbuf = NULL; 3468 char_u buf[NUMBUFLEN]; 3469 3470 fname = get_tv_string_chk(&argvars[0]); 3471 mods = get_tv_string_buf_chk(&argvars[1], buf); 3472 if (fname == NULL || mods == NULL) 3473 fname = NULL; 3474 else 3475 { 3476 len = (int)STRLEN(fname); 3477 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len); 3478 } 3479 3480 rettv->v_type = VAR_STRING; 3481 if (fname == NULL) 3482 rettv->vval.v_string = NULL; 3483 else 3484 rettv->vval.v_string = vim_strnsave(fname, len); 3485 vim_free(fbuf); 3486 } 3487 3488 static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end); 3489 3490 /* 3491 * "foldclosed()" function 3492 */ 3493 static void 3494 foldclosed_both( 3495 typval_T *argvars UNUSED, 3496 typval_T *rettv, 3497 int end UNUSED) 3498 { 3499 #ifdef FEAT_FOLDING 3500 linenr_T lnum; 3501 linenr_T first, last; 3502 3503 lnum = get_tv_lnum(argvars); 3504 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) 3505 { 3506 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL)) 3507 { 3508 if (end) 3509 rettv->vval.v_number = (varnumber_T)last; 3510 else 3511 rettv->vval.v_number = (varnumber_T)first; 3512 return; 3513 } 3514 } 3515 #endif 3516 rettv->vval.v_number = -1; 3517 } 3518 3519 /* 3520 * "foldclosed()" function 3521 */ 3522 static void 3523 f_foldclosed(typval_T *argvars, typval_T *rettv) 3524 { 3525 foldclosed_both(argvars, rettv, FALSE); 3526 } 3527 3528 /* 3529 * "foldclosedend()" function 3530 */ 3531 static void 3532 f_foldclosedend(typval_T *argvars, typval_T *rettv) 3533 { 3534 foldclosed_both(argvars, rettv, TRUE); 3535 } 3536 3537 /* 3538 * "foldlevel()" function 3539 */ 3540 static void 3541 f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 3542 { 3543 #ifdef FEAT_FOLDING 3544 linenr_T lnum; 3545 3546 lnum = get_tv_lnum(argvars); 3547 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) 3548 rettv->vval.v_number = foldLevel(lnum); 3549 #endif 3550 } 3551 3552 /* 3553 * "foldtext()" function 3554 */ 3555 static void 3556 f_foldtext(typval_T *argvars UNUSED, typval_T *rettv) 3557 { 3558 #ifdef FEAT_FOLDING 3559 linenr_T foldstart; 3560 linenr_T foldend; 3561 char_u *dashes; 3562 linenr_T lnum; 3563 char_u *s; 3564 char_u *r; 3565 int len; 3566 char *txt; 3567 long count; 3568 #endif 3569 3570 rettv->v_type = VAR_STRING; 3571 rettv->vval.v_string = NULL; 3572 #ifdef FEAT_FOLDING 3573 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART); 3574 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND); 3575 dashes = get_vim_var_str(VV_FOLDDASHES); 3576 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count 3577 && dashes != NULL) 3578 { 3579 /* Find first non-empty line in the fold. */ 3580 for (lnum = foldstart; lnum < foldend; ++lnum) 3581 if (!linewhite(lnum)) 3582 break; 3583 3584 /* Find interesting text in this line. */ 3585 s = skipwhite(ml_get(lnum)); 3586 /* skip C comment-start */ 3587 if (s[0] == '/' && (s[1] == '*' || s[1] == '/')) 3588 { 3589 s = skipwhite(s + 2); 3590 if (*skipwhite(s) == NUL 3591 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND)) 3592 { 3593 s = skipwhite(ml_get(lnum + 1)); 3594 if (*s == '*') 3595 s = skipwhite(s + 1); 3596 } 3597 } 3598 count = (long)(foldend - foldstart + 1); 3599 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count); 3600 r = alloc((unsigned)(STRLEN(txt) 3601 + STRLEN(dashes) /* for %s */ 3602 + 20 /* for %3ld */ 3603 + STRLEN(s))); /* concatenated */ 3604 if (r != NULL) 3605 { 3606 sprintf((char *)r, txt, dashes, count); 3607 len = (int)STRLEN(r); 3608 STRCAT(r, s); 3609 /* remove 'foldmarker' and 'commentstring' */ 3610 foldtext_cleanup(r + len); 3611 rettv->vval.v_string = r; 3612 } 3613 } 3614 #endif 3615 } 3616 3617 /* 3618 * "foldtextresult(lnum)" function 3619 */ 3620 static void 3621 f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv) 3622 { 3623 #ifdef FEAT_FOLDING 3624 linenr_T lnum; 3625 char_u *text; 3626 char_u buf[FOLD_TEXT_LEN]; 3627 foldinfo_T foldinfo; 3628 int fold_count; 3629 #endif 3630 3631 rettv->v_type = VAR_STRING; 3632 rettv->vval.v_string = NULL; 3633 #ifdef FEAT_FOLDING 3634 lnum = get_tv_lnum(argvars); 3635 /* treat illegal types and illegal string values for {lnum} the same */ 3636 if (lnum < 0) 3637 lnum = 0; 3638 fold_count = foldedCount(curwin, lnum, &foldinfo); 3639 if (fold_count > 0) 3640 { 3641 text = get_foldtext(curwin, lnum, lnum + fold_count - 1, 3642 &foldinfo, buf); 3643 if (text == buf) 3644 text = vim_strsave(text); 3645 rettv->vval.v_string = text; 3646 } 3647 #endif 3648 } 3649 3650 /* 3651 * "foreground()" function 3652 */ 3653 static void 3654 f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 3655 { 3656 #ifdef FEAT_GUI 3657 if (gui.in_use) 3658 gui_mch_set_foreground(); 3659 #else 3660 # ifdef WIN32 3661 win32_set_foreground(); 3662 # endif 3663 #endif 3664 } 3665 3666 static void 3667 common_function(typval_T *argvars, typval_T *rettv, int is_funcref) 3668 { 3669 char_u *s; 3670 char_u *name; 3671 int use_string = FALSE; 3672 partial_T *arg_pt = NULL; 3673 char_u *trans_name = NULL; 3674 3675 if (argvars[0].v_type == VAR_FUNC) 3676 { 3677 /* function(MyFunc, [arg], dict) */ 3678 s = argvars[0].vval.v_string; 3679 } 3680 else if (argvars[0].v_type == VAR_PARTIAL 3681 && argvars[0].vval.v_partial != NULL) 3682 { 3683 /* function(dict.MyFunc, [arg]) */ 3684 arg_pt = argvars[0].vval.v_partial; 3685 s = partial_name(arg_pt); 3686 } 3687 else 3688 { 3689 /* function('MyFunc', [arg], dict) */ 3690 s = get_tv_string(&argvars[0]); 3691 use_string = TRUE; 3692 } 3693 3694 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref) 3695 { 3696 name = s; 3697 trans_name = trans_function_name(&name, FALSE, 3698 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL); 3699 if (*name != NUL) 3700 s = NULL; 3701 } 3702 3703 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)) 3704 || (is_funcref && trans_name == NULL)) 3705 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s); 3706 /* Don't check an autoload name for existence here. */ 3707 else if (trans_name != NULL && (is_funcref 3708 ? find_func(trans_name) == NULL 3709 : !translated_function_exists(trans_name))) 3710 EMSG2(_("E700: Unknown function: %s"), s); 3711 else 3712 { 3713 int dict_idx = 0; 3714 int arg_idx = 0; 3715 list_T *list = NULL; 3716 3717 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0) 3718 { 3719 char sid_buf[25]; 3720 int off = *s == 's' ? 2 : 5; 3721 3722 /* Expand s: and <SID> into <SNR>nr_, so that the function can 3723 * also be called from another script. Using trans_function_name() 3724 * would also work, but some plugins depend on the name being 3725 * printable text. */ 3726 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID); 3727 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1)); 3728 if (name != NULL) 3729 { 3730 STRCPY(name, sid_buf); 3731 STRCAT(name, s + off); 3732 } 3733 } 3734 else 3735 name = vim_strsave(s); 3736 3737 if (argvars[1].v_type != VAR_UNKNOWN) 3738 { 3739 if (argvars[2].v_type != VAR_UNKNOWN) 3740 { 3741 /* function(name, [args], dict) */ 3742 arg_idx = 1; 3743 dict_idx = 2; 3744 } 3745 else if (argvars[1].v_type == VAR_DICT) 3746 /* function(name, dict) */ 3747 dict_idx = 1; 3748 else 3749 /* function(name, [args]) */ 3750 arg_idx = 1; 3751 if (dict_idx > 0) 3752 { 3753 if (argvars[dict_idx].v_type != VAR_DICT) 3754 { 3755 EMSG(_("E922: expected a dict")); 3756 vim_free(name); 3757 goto theend; 3758 } 3759 if (argvars[dict_idx].vval.v_dict == NULL) 3760 dict_idx = 0; 3761 } 3762 if (arg_idx > 0) 3763 { 3764 if (argvars[arg_idx].v_type != VAR_LIST) 3765 { 3766 EMSG(_("E923: Second argument of function() must be a list or a dict")); 3767 vim_free(name); 3768 goto theend; 3769 } 3770 list = argvars[arg_idx].vval.v_list; 3771 if (list == NULL || list->lv_len == 0) 3772 arg_idx = 0; 3773 } 3774 } 3775 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref) 3776 { 3777 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T)); 3778 3779 /* result is a VAR_PARTIAL */ 3780 if (pt == NULL) 3781 vim_free(name); 3782 else 3783 { 3784 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0)) 3785 { 3786 listitem_T *li; 3787 int i = 0; 3788 int arg_len = 0; 3789 int lv_len = 0; 3790 3791 if (arg_pt != NULL) 3792 arg_len = arg_pt->pt_argc; 3793 if (list != NULL) 3794 lv_len = list->lv_len; 3795 pt->pt_argc = arg_len + lv_len; 3796 pt->pt_argv = (typval_T *)alloc( 3797 sizeof(typval_T) * pt->pt_argc); 3798 if (pt->pt_argv == NULL) 3799 { 3800 vim_free(pt); 3801 vim_free(name); 3802 goto theend; 3803 } 3804 for (i = 0; i < arg_len; i++) 3805 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]); 3806 if (lv_len > 0) 3807 for (li = list->lv_first; li != NULL; 3808 li = li->li_next) 3809 copy_tv(&li->li_tv, &pt->pt_argv[i++]); 3810 } 3811 3812 /* For "function(dict.func, [], dict)" and "func" is a partial 3813 * use "dict". That is backwards compatible. */ 3814 if (dict_idx > 0) 3815 { 3816 /* The dict is bound explicitly, pt_auto is FALSE. */ 3817 pt->pt_dict = argvars[dict_idx].vval.v_dict; 3818 ++pt->pt_dict->dv_refcount; 3819 } 3820 else if (arg_pt != NULL) 3821 { 3822 /* If the dict was bound automatically the result is also 3823 * bound automatically. */ 3824 pt->pt_dict = arg_pt->pt_dict; 3825 pt->pt_auto = arg_pt->pt_auto; 3826 if (pt->pt_dict != NULL) 3827 ++pt->pt_dict->dv_refcount; 3828 } 3829 3830 pt->pt_refcount = 1; 3831 if (arg_pt != NULL && arg_pt->pt_func != NULL) 3832 { 3833 pt->pt_func = arg_pt->pt_func; 3834 func_ptr_ref(pt->pt_func); 3835 vim_free(name); 3836 } 3837 else if (is_funcref) 3838 { 3839 pt->pt_func = find_func(trans_name); 3840 func_ptr_ref(pt->pt_func); 3841 vim_free(name); 3842 } 3843 else 3844 { 3845 pt->pt_name = name; 3846 func_ref(name); 3847 } 3848 } 3849 rettv->v_type = VAR_PARTIAL; 3850 rettv->vval.v_partial = pt; 3851 } 3852 else 3853 { 3854 /* result is a VAR_FUNC */ 3855 rettv->v_type = VAR_FUNC; 3856 rettv->vval.v_string = name; 3857 func_ref(name); 3858 } 3859 } 3860 theend: 3861 vim_free(trans_name); 3862 } 3863 3864 /* 3865 * "funcref()" function 3866 */ 3867 static void 3868 f_funcref(typval_T *argvars, typval_T *rettv) 3869 { 3870 common_function(argvars, rettv, TRUE); 3871 } 3872 3873 /* 3874 * "function()" function 3875 */ 3876 static void 3877 f_function(typval_T *argvars, typval_T *rettv) 3878 { 3879 common_function(argvars, rettv, FALSE); 3880 } 3881 3882 /* 3883 * "garbagecollect()" function 3884 */ 3885 static void 3886 f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED) 3887 { 3888 /* This is postponed until we are back at the toplevel, because we may be 3889 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */ 3890 want_garbage_collect = TRUE; 3891 3892 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1) 3893 garbage_collect_at_exit = TRUE; 3894 } 3895 3896 /* 3897 * "get()" function 3898 */ 3899 static void 3900 f_get(typval_T *argvars, typval_T *rettv) 3901 { 3902 listitem_T *li; 3903 list_T *l; 3904 dictitem_T *di; 3905 dict_T *d; 3906 typval_T *tv = NULL; 3907 3908 if (argvars[0].v_type == VAR_LIST) 3909 { 3910 if ((l = argvars[0].vval.v_list) != NULL) 3911 { 3912 int error = FALSE; 3913 3914 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error)); 3915 if (!error && li != NULL) 3916 tv = &li->li_tv; 3917 } 3918 } 3919 else if (argvars[0].v_type == VAR_DICT) 3920 { 3921 if ((d = argvars[0].vval.v_dict) != NULL) 3922 { 3923 di = dict_find(d, get_tv_string(&argvars[1]), -1); 3924 if (di != NULL) 3925 tv = &di->di_tv; 3926 } 3927 } 3928 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC) 3929 { 3930 partial_T *pt; 3931 partial_T fref_pt; 3932 3933 if (argvars[0].v_type == VAR_PARTIAL) 3934 pt = argvars[0].vval.v_partial; 3935 else 3936 { 3937 vim_memset(&fref_pt, 0, sizeof(fref_pt)); 3938 fref_pt.pt_name = argvars[0].vval.v_string; 3939 pt = &fref_pt; 3940 } 3941 3942 if (pt != NULL) 3943 { 3944 char_u *what = get_tv_string(&argvars[1]); 3945 char_u *n; 3946 3947 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0) 3948 { 3949 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING); 3950 n = partial_name(pt); 3951 if (n == NULL) 3952 rettv->vval.v_string = NULL; 3953 else 3954 { 3955 rettv->vval.v_string = vim_strsave(n); 3956 if (rettv->v_type == VAR_FUNC) 3957 func_ref(rettv->vval.v_string); 3958 } 3959 } 3960 else if (STRCMP(what, "dict") == 0) 3961 rettv_dict_set(rettv, pt->pt_dict); 3962 else if (STRCMP(what, "args") == 0) 3963 { 3964 rettv->v_type = VAR_LIST; 3965 if (rettv_list_alloc(rettv) == OK) 3966 { 3967 int i; 3968 3969 for (i = 0; i < pt->pt_argc; ++i) 3970 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]); 3971 } 3972 } 3973 else 3974 EMSG2(_(e_invarg2), what); 3975 return; 3976 } 3977 } 3978 else 3979 EMSG2(_(e_listdictarg), "get()"); 3980 3981 if (tv == NULL) 3982 { 3983 if (argvars[2].v_type != VAR_UNKNOWN) 3984 copy_tv(&argvars[2], rettv); 3985 } 3986 else 3987 copy_tv(tv, rettv); 3988 } 3989 3990 #ifdef FEAT_SIGNS 3991 /* 3992 * Returns information about signs placed in a buffer as list of dicts. 3993 */ 3994 static void 3995 get_buffer_signs(buf_T *buf, list_T *l) 3996 { 3997 signlist_T *sign; 3998 3999 for (sign = buf->b_signlist; sign; sign = sign->next) 4000 { 4001 dict_T *d = dict_alloc(); 4002 4003 if (d != NULL) 4004 { 4005 dict_add_nr_str(d, "id", sign->id, NULL); 4006 dict_add_nr_str(d, "lnum", sign->lnum, NULL); 4007 dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr)); 4008 4009 list_append_dict(l, d); 4010 } 4011 } 4012 } 4013 #endif 4014 4015 /* 4016 * Returns buffer options, variables and other attributes in a dictionary. 4017 */ 4018 static dict_T * 4019 get_buffer_info(buf_T *buf) 4020 { 4021 dict_T *dict; 4022 tabpage_T *tp; 4023 win_T *wp; 4024 list_T *windows; 4025 4026 dict = dict_alloc(); 4027 if (dict == NULL) 4028 return NULL; 4029 4030 dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL); 4031 dict_add_nr_str(dict, "name", 0L, 4032 buf->b_ffname != NULL ? buf->b_ffname : (char_u *)""); 4033 dict_add_nr_str(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum 4034 : buflist_findlnum(buf), NULL); 4035 dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL); 4036 dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL); 4037 dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL); 4038 dict_add_nr_str(dict, "changedtick", CHANGEDTICK(buf), NULL); 4039 dict_add_nr_str(dict, "hidden", 4040 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0, 4041 NULL); 4042 4043 /* Get a reference to buffer variables */ 4044 dict_add_dict(dict, "variables", buf->b_vars); 4045 4046 /* List of windows displaying this buffer */ 4047 windows = list_alloc(); 4048 if (windows != NULL) 4049 { 4050 FOR_ALL_TAB_WINDOWS(tp, wp) 4051 if (wp->w_buffer == buf) 4052 list_append_number(windows, (varnumber_T)wp->w_id); 4053 dict_add_list(dict, "windows", windows); 4054 } 4055 4056 #ifdef FEAT_SIGNS 4057 if (buf->b_signlist != NULL) 4058 { 4059 /* List of signs placed in this buffer */ 4060 list_T *signs = list_alloc(); 4061 if (signs != NULL) 4062 { 4063 get_buffer_signs(buf, signs); 4064 dict_add_list(dict, "signs", signs); 4065 } 4066 } 4067 #endif 4068 4069 return dict; 4070 } 4071 4072 /* 4073 * "getbufinfo()" function 4074 */ 4075 static void 4076 f_getbufinfo(typval_T *argvars, typval_T *rettv) 4077 { 4078 buf_T *buf = NULL; 4079 buf_T *argbuf = NULL; 4080 dict_T *d; 4081 int filtered = FALSE; 4082 int sel_buflisted = FALSE; 4083 int sel_bufloaded = FALSE; 4084 4085 if (rettv_list_alloc(rettv) != OK) 4086 return; 4087 4088 /* List of all the buffers or selected buffers */ 4089 if (argvars[0].v_type == VAR_DICT) 4090 { 4091 dict_T *sel_d = argvars[0].vval.v_dict; 4092 4093 if (sel_d != NULL) 4094 { 4095 dictitem_T *di; 4096 4097 filtered = TRUE; 4098 4099 di = dict_find(sel_d, (char_u *)"buflisted", -1); 4100 if (di != NULL && get_tv_number(&di->di_tv)) 4101 sel_buflisted = TRUE; 4102 4103 di = dict_find(sel_d, (char_u *)"bufloaded", -1); 4104 if (di != NULL && get_tv_number(&di->di_tv)) 4105 sel_bufloaded = TRUE; 4106 } 4107 } 4108 else if (argvars[0].v_type != VAR_UNKNOWN) 4109 { 4110 /* Information about one buffer. Argument specifies the buffer */ 4111 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ 4112 ++emsg_off; 4113 argbuf = get_buf_tv(&argvars[0], FALSE); 4114 --emsg_off; 4115 if (argbuf == NULL) 4116 return; 4117 } 4118 4119 /* Return information about all the buffers or a specified buffer */ 4120 FOR_ALL_BUFFERS(buf) 4121 { 4122 if (argbuf != NULL && argbuf != buf) 4123 continue; 4124 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL) 4125 || (sel_buflisted && !buf->b_p_bl))) 4126 continue; 4127 4128 d = get_buffer_info(buf); 4129 if (d != NULL) 4130 list_append_dict(rettv->vval.v_list, d); 4131 if (argbuf != NULL) 4132 return; 4133 } 4134 } 4135 4136 static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv); 4137 4138 /* 4139 * Get line or list of lines from buffer "buf" into "rettv". 4140 * Return a range (from start to end) of lines in rettv from the specified 4141 * buffer. 4142 * If 'retlist' is TRUE, then the lines are returned as a Vim List. 4143 */ 4144 static void 4145 get_buffer_lines( 4146 buf_T *buf, 4147 linenr_T start, 4148 linenr_T end, 4149 int retlist, 4150 typval_T *rettv) 4151 { 4152 char_u *p; 4153 4154 rettv->v_type = VAR_STRING; 4155 rettv->vval.v_string = NULL; 4156 if (retlist && rettv_list_alloc(rettv) == FAIL) 4157 return; 4158 4159 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0) 4160 return; 4161 4162 if (!retlist) 4163 { 4164 if (start >= 1 && start <= buf->b_ml.ml_line_count) 4165 p = ml_get_buf(buf, start, FALSE); 4166 else 4167 p = (char_u *)""; 4168 rettv->vval.v_string = vim_strsave(p); 4169 } 4170 else 4171 { 4172 if (end < start) 4173 return; 4174 4175 if (start < 1) 4176 start = 1; 4177 if (end > buf->b_ml.ml_line_count) 4178 end = buf->b_ml.ml_line_count; 4179 while (start <= end) 4180 if (list_append_string(rettv->vval.v_list, 4181 ml_get_buf(buf, start++, FALSE), -1) == FAIL) 4182 break; 4183 } 4184 } 4185 4186 /* 4187 * Get the lnum from the first argument. 4188 * Also accepts "$", then "buf" is used. 4189 * Returns 0 on error. 4190 */ 4191 static linenr_T 4192 get_tv_lnum_buf(typval_T *argvars, buf_T *buf) 4193 { 4194 if (argvars[0].v_type == VAR_STRING 4195 && argvars[0].vval.v_string != NULL 4196 && argvars[0].vval.v_string[0] == '$' 4197 && buf != NULL) 4198 return buf->b_ml.ml_line_count; 4199 return (linenr_T)get_tv_number_chk(&argvars[0], NULL); 4200 } 4201 4202 /* 4203 * "getbufline()" function 4204 */ 4205 static void 4206 f_getbufline(typval_T *argvars, typval_T *rettv) 4207 { 4208 linenr_T lnum; 4209 linenr_T end; 4210 buf_T *buf; 4211 4212 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ 4213 ++emsg_off; 4214 buf = get_buf_tv(&argvars[0], FALSE); 4215 --emsg_off; 4216 4217 lnum = get_tv_lnum_buf(&argvars[1], buf); 4218 if (argvars[2].v_type == VAR_UNKNOWN) 4219 end = lnum; 4220 else 4221 end = get_tv_lnum_buf(&argvars[2], buf); 4222 4223 get_buffer_lines(buf, lnum, end, TRUE, rettv); 4224 } 4225 4226 /* 4227 * "getbufvar()" function 4228 */ 4229 static void 4230 f_getbufvar(typval_T *argvars, typval_T *rettv) 4231 { 4232 buf_T *buf; 4233 buf_T *save_curbuf; 4234 char_u *varname; 4235 dictitem_T *v; 4236 int done = FALSE; 4237 4238 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ 4239 varname = get_tv_string_chk(&argvars[1]); 4240 ++emsg_off; 4241 buf = get_buf_tv(&argvars[0], FALSE); 4242 4243 rettv->v_type = VAR_STRING; 4244 rettv->vval.v_string = NULL; 4245 4246 if (buf != NULL && varname != NULL) 4247 { 4248 /* set curbuf to be our buf, temporarily */ 4249 save_curbuf = curbuf; 4250 curbuf = buf; 4251 4252 if (*varname == '&') 4253 { 4254 if (varname[1] == NUL) 4255 { 4256 /* get all buffer-local options in a dict */ 4257 dict_T *opts = get_winbuf_options(TRUE); 4258 4259 if (opts != NULL) 4260 { 4261 rettv_dict_set(rettv, opts); 4262 done = TRUE; 4263 } 4264 } 4265 else if (get_option_tv(&varname, rettv, TRUE) == OK) 4266 /* buffer-local-option */ 4267 done = TRUE; 4268 } 4269 else 4270 { 4271 /* Look up the variable. */ 4272 /* Let getbufvar({nr}, "") return the "b:" dictionary. */ 4273 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab, 4274 'b', varname, FALSE); 4275 if (v != NULL) 4276 { 4277 copy_tv(&v->di_tv, rettv); 4278 done = TRUE; 4279 } 4280 } 4281 4282 /* restore previous notion of curbuf */ 4283 curbuf = save_curbuf; 4284 } 4285 4286 if (!done && argvars[2].v_type != VAR_UNKNOWN) 4287 /* use the default value */ 4288 copy_tv(&argvars[2], rettv); 4289 4290 --emsg_off; 4291 } 4292 4293 /* 4294 * "getchar()" function 4295 */ 4296 static void 4297 f_getchar(typval_T *argvars, typval_T *rettv) 4298 { 4299 varnumber_T n; 4300 int error = FALSE; 4301 4302 /* Position the cursor. Needed after a message that ends in a space. */ 4303 windgoto(msg_row, msg_col); 4304 4305 ++no_mapping; 4306 ++allow_keys; 4307 for (;;) 4308 { 4309 if (argvars[0].v_type == VAR_UNKNOWN) 4310 /* getchar(): blocking wait. */ 4311 n = plain_vgetc(); 4312 else if (get_tv_number_chk(&argvars[0], &error) == 1) 4313 /* getchar(1): only check if char avail */ 4314 n = vpeekc_any(); 4315 else if (error || vpeekc_any() == NUL) 4316 /* illegal argument or getchar(0) and no char avail: return zero */ 4317 n = 0; 4318 else 4319 /* getchar(0) and char avail: return char */ 4320 n = plain_vgetc(); 4321 4322 if (n == K_IGNORE) 4323 continue; 4324 break; 4325 } 4326 --no_mapping; 4327 --allow_keys; 4328 4329 set_vim_var_nr(VV_MOUSE_WIN, 0); 4330 set_vim_var_nr(VV_MOUSE_WINID, 0); 4331 set_vim_var_nr(VV_MOUSE_LNUM, 0); 4332 set_vim_var_nr(VV_MOUSE_COL, 0); 4333 4334 rettv->vval.v_number = n; 4335 if (IS_SPECIAL(n) || mod_mask != 0) 4336 { 4337 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */ 4338 int i = 0; 4339 4340 /* Turn a special key into three bytes, plus modifier. */ 4341 if (mod_mask != 0) 4342 { 4343 temp[i++] = K_SPECIAL; 4344 temp[i++] = KS_MODIFIER; 4345 temp[i++] = mod_mask; 4346 } 4347 if (IS_SPECIAL(n)) 4348 { 4349 temp[i++] = K_SPECIAL; 4350 temp[i++] = K_SECOND(n); 4351 temp[i++] = K_THIRD(n); 4352 } 4353 #ifdef FEAT_MBYTE 4354 else if (has_mbyte) 4355 i += (*mb_char2bytes)(n, temp + i); 4356 #endif 4357 else 4358 temp[i++] = n; 4359 temp[i++] = NUL; 4360 rettv->v_type = VAR_STRING; 4361 rettv->vval.v_string = vim_strsave(temp); 4362 4363 #ifdef FEAT_MOUSE 4364 if (is_mouse_key(n)) 4365 { 4366 int row = mouse_row; 4367 int col = mouse_col; 4368 win_T *win; 4369 linenr_T lnum; 4370 # ifdef FEAT_WINDOWS 4371 win_T *wp; 4372 # endif 4373 int winnr = 1; 4374 4375 if (row >= 0 && col >= 0) 4376 { 4377 /* Find the window at the mouse coordinates and compute the 4378 * text position. */ 4379 win = mouse_find_win(&row, &col); 4380 (void)mouse_comp_pos(win, &row, &col, &lnum); 4381 # ifdef FEAT_WINDOWS 4382 for (wp = firstwin; wp != win; wp = wp->w_next) 4383 ++winnr; 4384 # endif 4385 set_vim_var_nr(VV_MOUSE_WIN, winnr); 4386 set_vim_var_nr(VV_MOUSE_WINID, win->w_id); 4387 set_vim_var_nr(VV_MOUSE_LNUM, lnum); 4388 set_vim_var_nr(VV_MOUSE_COL, col + 1); 4389 } 4390 } 4391 #endif 4392 } 4393 } 4394 4395 /* 4396 * "getcharmod()" function 4397 */ 4398 static void 4399 f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv) 4400 { 4401 rettv->vval.v_number = mod_mask; 4402 } 4403 4404 /* 4405 * "getcharsearch()" function 4406 */ 4407 static void 4408 f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv) 4409 { 4410 if (rettv_dict_alloc(rettv) != FAIL) 4411 { 4412 dict_T *dict = rettv->vval.v_dict; 4413 4414 dict_add_nr_str(dict, "char", 0L, last_csearch()); 4415 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL); 4416 dict_add_nr_str(dict, "until", last_csearch_until(), NULL); 4417 } 4418 } 4419 4420 /* 4421 * "getcmdline()" function 4422 */ 4423 static void 4424 f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv) 4425 { 4426 rettv->v_type = VAR_STRING; 4427 rettv->vval.v_string = get_cmdline_str(); 4428 } 4429 4430 /* 4431 * "getcmdpos()" function 4432 */ 4433 static void 4434 f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv) 4435 { 4436 rettv->vval.v_number = get_cmdline_pos() + 1; 4437 } 4438 4439 /* 4440 * "getcmdtype()" function 4441 */ 4442 static void 4443 f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv) 4444 { 4445 rettv->v_type = VAR_STRING; 4446 rettv->vval.v_string = alloc(2); 4447 if (rettv->vval.v_string != NULL) 4448 { 4449 rettv->vval.v_string[0] = get_cmdline_type(); 4450 rettv->vval.v_string[1] = NUL; 4451 } 4452 } 4453 4454 /* 4455 * "getcmdwintype()" function 4456 */ 4457 static void 4458 f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv) 4459 { 4460 rettv->v_type = VAR_STRING; 4461 rettv->vval.v_string = NULL; 4462 #ifdef FEAT_CMDWIN 4463 rettv->vval.v_string = alloc(2); 4464 if (rettv->vval.v_string != NULL) 4465 { 4466 rettv->vval.v_string[0] = cmdwin_type; 4467 rettv->vval.v_string[1] = NUL; 4468 } 4469 #endif 4470 } 4471 4472 #if defined(FEAT_CMDL_COMPL) 4473 /* 4474 * "getcompletion()" function 4475 */ 4476 static void 4477 f_getcompletion(typval_T *argvars, typval_T *rettv) 4478 { 4479 char_u *pat; 4480 expand_T xpc; 4481 int filtered = FALSE; 4482 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH 4483 | WILD_NO_BEEP; 4484 4485 if (argvars[2].v_type != VAR_UNKNOWN) 4486 filtered = get_tv_number_chk(&argvars[2], NULL); 4487 4488 if (p_wic) 4489 options |= WILD_ICASE; 4490 4491 /* For filtered results, 'wildignore' is used */ 4492 if (!filtered) 4493 options |= WILD_KEEP_ALL; 4494 4495 ExpandInit(&xpc); 4496 xpc.xp_pattern = get_tv_string(&argvars[0]); 4497 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); 4498 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1])); 4499 if (xpc.xp_context == EXPAND_NOTHING) 4500 { 4501 if (argvars[1].v_type == VAR_STRING) 4502 EMSG2(_(e_invarg2), argvars[1].vval.v_string); 4503 else 4504 EMSG(_(e_invarg)); 4505 return; 4506 } 4507 4508 # if defined(FEAT_MENU) 4509 if (xpc.xp_context == EXPAND_MENUS) 4510 { 4511 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE); 4512 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); 4513 } 4514 # endif 4515 #ifdef FEAT_CSCOPE 4516 if (xpc.xp_context == EXPAND_CSCOPE) 4517 { 4518 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope); 4519 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); 4520 } 4521 #endif 4522 #ifdef FEAT_SIGNS 4523 if (xpc.xp_context == EXPAND_SIGN) 4524 { 4525 set_context_in_sign_cmd(&xpc, xpc.xp_pattern); 4526 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); 4527 } 4528 #endif 4529 4530 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context); 4531 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL)) 4532 { 4533 int i; 4534 4535 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP); 4536 4537 for (i = 0; i < xpc.xp_numfiles; i++) 4538 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); 4539 } 4540 vim_free(pat); 4541 ExpandCleanup(&xpc); 4542 } 4543 #endif 4544 4545 /* 4546 * "getcwd()" function 4547 */ 4548 static void 4549 f_getcwd(typval_T *argvars, typval_T *rettv) 4550 { 4551 win_T *wp = NULL; 4552 char_u *cwd; 4553 4554 rettv->v_type = VAR_STRING; 4555 rettv->vval.v_string = NULL; 4556 4557 wp = find_tabwin(&argvars[0], &argvars[1]); 4558 if (wp != NULL) 4559 { 4560 if (wp->w_localdir != NULL) 4561 rettv->vval.v_string = vim_strsave(wp->w_localdir); 4562 else if (globaldir != NULL) 4563 rettv->vval.v_string = vim_strsave(globaldir); 4564 else 4565 { 4566 cwd = alloc(MAXPATHL); 4567 if (cwd != NULL) 4568 { 4569 if (mch_dirname(cwd, MAXPATHL) != FAIL) 4570 rettv->vval.v_string = vim_strsave(cwd); 4571 vim_free(cwd); 4572 } 4573 } 4574 #ifdef BACKSLASH_IN_FILENAME 4575 if (rettv->vval.v_string != NULL) 4576 slash_adjust(rettv->vval.v_string); 4577 #endif 4578 } 4579 } 4580 4581 /* 4582 * "getfontname()" function 4583 */ 4584 static void 4585 f_getfontname(typval_T *argvars UNUSED, typval_T *rettv) 4586 { 4587 rettv->v_type = VAR_STRING; 4588 rettv->vval.v_string = NULL; 4589 #ifdef FEAT_GUI 4590 if (gui.in_use) 4591 { 4592 GuiFont font; 4593 char_u *name = NULL; 4594 4595 if (argvars[0].v_type == VAR_UNKNOWN) 4596 { 4597 /* Get the "Normal" font. Either the name saved by 4598 * hl_set_font_name() or from the font ID. */ 4599 font = gui.norm_font; 4600 name = hl_get_font_name(); 4601 } 4602 else 4603 { 4604 name = get_tv_string(&argvars[0]); 4605 if (STRCMP(name, "*") == 0) /* don't use font dialog */ 4606 return; 4607 font = gui_mch_get_font(name, FALSE); 4608 if (font == NOFONT) 4609 return; /* Invalid font name, return empty string. */ 4610 } 4611 rettv->vval.v_string = gui_mch_get_fontname(font, name); 4612 if (argvars[0].v_type != VAR_UNKNOWN) 4613 gui_mch_free_font(font); 4614 } 4615 #endif 4616 } 4617 4618 /* 4619 * "getfperm({fname})" function 4620 */ 4621 static void 4622 f_getfperm(typval_T *argvars, typval_T *rettv) 4623 { 4624 char_u *fname; 4625 stat_T st; 4626 char_u *perm = NULL; 4627 char_u flags[] = "rwx"; 4628 int i; 4629 4630 fname = get_tv_string(&argvars[0]); 4631 4632 rettv->v_type = VAR_STRING; 4633 if (mch_stat((char *)fname, &st) >= 0) 4634 { 4635 perm = vim_strsave((char_u *)"---------"); 4636 if (perm != NULL) 4637 { 4638 for (i = 0; i < 9; i++) 4639 { 4640 if (st.st_mode & (1 << (8 - i))) 4641 perm[i] = flags[i % 3]; 4642 } 4643 } 4644 } 4645 rettv->vval.v_string = perm; 4646 } 4647 4648 /* 4649 * "getfsize({fname})" function 4650 */ 4651 static void 4652 f_getfsize(typval_T *argvars, typval_T *rettv) 4653 { 4654 char_u *fname; 4655 stat_T st; 4656 4657 fname = get_tv_string(&argvars[0]); 4658 4659 rettv->v_type = VAR_NUMBER; 4660 4661 if (mch_stat((char *)fname, &st) >= 0) 4662 { 4663 if (mch_isdir(fname)) 4664 rettv->vval.v_number = 0; 4665 else 4666 { 4667 rettv->vval.v_number = (varnumber_T)st.st_size; 4668 4669 /* non-perfect check for overflow */ 4670 if ((off_T)rettv->vval.v_number != (off_T)st.st_size) 4671 rettv->vval.v_number = -2; 4672 } 4673 } 4674 else 4675 rettv->vval.v_number = -1; 4676 } 4677 4678 /* 4679 * "getftime({fname})" function 4680 */ 4681 static void 4682 f_getftime(typval_T *argvars, typval_T *rettv) 4683 { 4684 char_u *fname; 4685 stat_T st; 4686 4687 fname = get_tv_string(&argvars[0]); 4688 4689 if (mch_stat((char *)fname, &st) >= 0) 4690 rettv->vval.v_number = (varnumber_T)st.st_mtime; 4691 else 4692 rettv->vval.v_number = -1; 4693 } 4694 4695 /* 4696 * "getftype({fname})" function 4697 */ 4698 static void 4699 f_getftype(typval_T *argvars, typval_T *rettv) 4700 { 4701 char_u *fname; 4702 stat_T st; 4703 char_u *type = NULL; 4704 char *t; 4705 4706 fname = get_tv_string(&argvars[0]); 4707 4708 rettv->v_type = VAR_STRING; 4709 if (mch_lstat((char *)fname, &st) >= 0) 4710 { 4711 #ifdef S_ISREG 4712 if (S_ISREG(st.st_mode)) 4713 t = "file"; 4714 else if (S_ISDIR(st.st_mode)) 4715 t = "dir"; 4716 # ifdef S_ISLNK 4717 else if (S_ISLNK(st.st_mode)) 4718 t = "link"; 4719 # endif 4720 # ifdef S_ISBLK 4721 else if (S_ISBLK(st.st_mode)) 4722 t = "bdev"; 4723 # endif 4724 # ifdef S_ISCHR 4725 else if (S_ISCHR(st.st_mode)) 4726 t = "cdev"; 4727 # endif 4728 # ifdef S_ISFIFO 4729 else if (S_ISFIFO(st.st_mode)) 4730 t = "fifo"; 4731 # endif 4732 # ifdef S_ISSOCK 4733 else if (S_ISSOCK(st.st_mode)) 4734 t = "fifo"; 4735 # endif 4736 else 4737 t = "other"; 4738 #else 4739 # ifdef S_IFMT 4740 switch (st.st_mode & S_IFMT) 4741 { 4742 case S_IFREG: t = "file"; break; 4743 case S_IFDIR: t = "dir"; break; 4744 # ifdef S_IFLNK 4745 case S_IFLNK: t = "link"; break; 4746 # endif 4747 # ifdef S_IFBLK 4748 case S_IFBLK: t = "bdev"; break; 4749 # endif 4750 # ifdef S_IFCHR 4751 case S_IFCHR: t = "cdev"; break; 4752 # endif 4753 # ifdef S_IFIFO 4754 case S_IFIFO: t = "fifo"; break; 4755 # endif 4756 # ifdef S_IFSOCK 4757 case S_IFSOCK: t = "socket"; break; 4758 # endif 4759 default: t = "other"; 4760 } 4761 # else 4762 if (mch_isdir(fname)) 4763 t = "dir"; 4764 else 4765 t = "file"; 4766 # endif 4767 #endif 4768 type = vim_strsave((char_u *)t); 4769 } 4770 rettv->vval.v_string = type; 4771 } 4772 4773 /* 4774 * "getline(lnum, [end])" function 4775 */ 4776 static void 4777 f_getline(typval_T *argvars, typval_T *rettv) 4778 { 4779 linenr_T lnum; 4780 linenr_T end; 4781 int retlist; 4782 4783 lnum = get_tv_lnum(argvars); 4784 if (argvars[1].v_type == VAR_UNKNOWN) 4785 { 4786 end = 0; 4787 retlist = FALSE; 4788 } 4789 else 4790 { 4791 end = get_tv_lnum(&argvars[1]); 4792 retlist = TRUE; 4793 } 4794 4795 get_buffer_lines(curbuf, lnum, end, retlist, rettv); 4796 } 4797 4798 #ifdef FEAT_QUICKFIX 4799 static void 4800 get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv) 4801 { 4802 if (what_arg->v_type == VAR_UNKNOWN) 4803 { 4804 if (rettv_list_alloc(rettv) == OK) 4805 if (is_qf || wp != NULL) 4806 (void)get_errorlist(wp, -1, rettv->vval.v_list); 4807 } 4808 else 4809 { 4810 if (rettv_dict_alloc(rettv) == OK) 4811 if (is_qf || (wp != NULL)) 4812 { 4813 if (what_arg->v_type == VAR_DICT) 4814 { 4815 dict_T *d = what_arg->vval.v_dict; 4816 4817 if (d != NULL) 4818 get_errorlist_properties(wp, d, rettv->vval.v_dict); 4819 } 4820 else 4821 EMSG(_(e_dictreq)); 4822 } 4823 } 4824 } 4825 #endif 4826 4827 /* 4828 * "getloclist()" function 4829 */ 4830 static void 4831 f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 4832 { 4833 #ifdef FEAT_QUICKFIX 4834 win_T *wp; 4835 4836 wp = find_win_by_nr(&argvars[0], NULL); 4837 get_qf_loc_list(FALSE, wp, &argvars[1], rettv); 4838 #endif 4839 } 4840 4841 /* 4842 * "getmatches()" function 4843 */ 4844 static void 4845 f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 4846 { 4847 #ifdef FEAT_SEARCH_EXTRA 4848 dict_T *dict; 4849 matchitem_T *cur = curwin->w_match_head; 4850 int i; 4851 4852 if (rettv_list_alloc(rettv) == OK) 4853 { 4854 while (cur != NULL) 4855 { 4856 dict = dict_alloc(); 4857 if (dict == NULL) 4858 return; 4859 if (cur->match.regprog == NULL) 4860 { 4861 /* match added with matchaddpos() */ 4862 for (i = 0; i < MAXPOSMATCH; ++i) 4863 { 4864 llpos_T *llpos; 4865 char buf[6]; 4866 list_T *l; 4867 4868 llpos = &cur->pos.pos[i]; 4869 if (llpos->lnum == 0) 4870 break; 4871 l = list_alloc(); 4872 if (l == NULL) 4873 break; 4874 list_append_number(l, (varnumber_T)llpos->lnum); 4875 if (llpos->col > 0) 4876 { 4877 list_append_number(l, (varnumber_T)llpos->col); 4878 list_append_number(l, (varnumber_T)llpos->len); 4879 } 4880 sprintf(buf, "pos%d", i + 1); 4881 dict_add_list(dict, buf, l); 4882 } 4883 } 4884 else 4885 { 4886 dict_add_nr_str(dict, "pattern", 0L, cur->pattern); 4887 } 4888 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id)); 4889 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL); 4890 dict_add_nr_str(dict, "id", (long)cur->id, NULL); 4891 # if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE) 4892 if (cur->conceal_char) 4893 { 4894 char_u buf[MB_MAXBYTES + 1]; 4895 4896 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL; 4897 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf); 4898 } 4899 # endif 4900 list_append_dict(rettv->vval.v_list, dict); 4901 cur = cur->next; 4902 } 4903 } 4904 #endif 4905 } 4906 4907 /* 4908 * "getpid()" function 4909 */ 4910 static void 4911 f_getpid(typval_T *argvars UNUSED, typval_T *rettv) 4912 { 4913 rettv->vval.v_number = mch_get_pid(); 4914 } 4915 4916 static void 4917 getpos_both( 4918 typval_T *argvars, 4919 typval_T *rettv, 4920 int getcurpos) 4921 { 4922 pos_T *fp; 4923 list_T *l; 4924 int fnum = -1; 4925 4926 if (rettv_list_alloc(rettv) == OK) 4927 { 4928 l = rettv->vval.v_list; 4929 if (getcurpos) 4930 fp = &curwin->w_cursor; 4931 else 4932 fp = var2fpos(&argvars[0], TRUE, &fnum); 4933 if (fnum != -1) 4934 list_append_number(l, (varnumber_T)fnum); 4935 else 4936 list_append_number(l, (varnumber_T)0); 4937 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum 4938 : (varnumber_T)0); 4939 list_append_number(l, (fp != NULL) 4940 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1) 4941 : (varnumber_T)0); 4942 list_append_number(l, 4943 #ifdef FEAT_VIRTUALEDIT 4944 (fp != NULL) ? (varnumber_T)fp->coladd : 4945 #endif 4946 (varnumber_T)0); 4947 if (getcurpos) 4948 { 4949 update_curswant(); 4950 list_append_number(l, curwin->w_curswant == MAXCOL ? 4951 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1); 4952 } 4953 } 4954 else 4955 rettv->vval.v_number = FALSE; 4956 } 4957 4958 4959 /* 4960 * "getcurpos()" function 4961 */ 4962 static void 4963 f_getcurpos(typval_T *argvars, typval_T *rettv) 4964 { 4965 getpos_both(argvars, rettv, TRUE); 4966 } 4967 4968 /* 4969 * "getpos(string)" function 4970 */ 4971 static void 4972 f_getpos(typval_T *argvars, typval_T *rettv) 4973 { 4974 getpos_both(argvars, rettv, FALSE); 4975 } 4976 4977 /* 4978 * "getqflist()" function 4979 */ 4980 static void 4981 f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 4982 { 4983 #ifdef FEAT_QUICKFIX 4984 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv); 4985 #endif 4986 } 4987 4988 /* 4989 * "getreg()" function 4990 */ 4991 static void 4992 f_getreg(typval_T *argvars, typval_T *rettv) 4993 { 4994 char_u *strregname; 4995 int regname; 4996 int arg2 = FALSE; 4997 int return_list = FALSE; 4998 int error = FALSE; 4999 5000 if (argvars[0].v_type != VAR_UNKNOWN) 5001 { 5002 strregname = get_tv_string_chk(&argvars[0]); 5003 error = strregname == NULL; 5004 if (argvars[1].v_type != VAR_UNKNOWN) 5005 { 5006 arg2 = (int)get_tv_number_chk(&argvars[1], &error); 5007 if (!error && argvars[2].v_type != VAR_UNKNOWN) 5008 return_list = (int)get_tv_number_chk(&argvars[2], &error); 5009 } 5010 } 5011 else 5012 strregname = get_vim_var_str(VV_REG); 5013 5014 if (error) 5015 return; 5016 5017 regname = (strregname == NULL ? '"' : *strregname); 5018 if (regname == 0) 5019 regname = '"'; 5020 5021 if (return_list) 5022 { 5023 rettv->v_type = VAR_LIST; 5024 rettv->vval.v_list = (list_T *)get_reg_contents(regname, 5025 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST); 5026 if (rettv->vval.v_list == NULL) 5027 (void)rettv_list_alloc(rettv); 5028 else 5029 ++rettv->vval.v_list->lv_refcount; 5030 } 5031 else 5032 { 5033 rettv->v_type = VAR_STRING; 5034 rettv->vval.v_string = get_reg_contents(regname, 5035 arg2 ? GREG_EXPR_SRC : 0); 5036 } 5037 } 5038 5039 /* 5040 * "getregtype()" function 5041 */ 5042 static void 5043 f_getregtype(typval_T *argvars, typval_T *rettv) 5044 { 5045 char_u *strregname; 5046 int regname; 5047 char_u buf[NUMBUFLEN + 2]; 5048 long reglen = 0; 5049 5050 if (argvars[0].v_type != VAR_UNKNOWN) 5051 { 5052 strregname = get_tv_string_chk(&argvars[0]); 5053 if (strregname == NULL) /* type error; errmsg already given */ 5054 { 5055 rettv->v_type = VAR_STRING; 5056 rettv->vval.v_string = NULL; 5057 return; 5058 } 5059 } 5060 else 5061 /* Default to v:register */ 5062 strregname = get_vim_var_str(VV_REG); 5063 5064 regname = (strregname == NULL ? '"' : *strregname); 5065 if (regname == 0) 5066 regname = '"'; 5067 5068 buf[0] = NUL; 5069 buf[1] = NUL; 5070 switch (get_reg_type(regname, ®len)) 5071 { 5072 case MLINE: buf[0] = 'V'; break; 5073 case MCHAR: buf[0] = 'v'; break; 5074 case MBLOCK: 5075 buf[0] = Ctrl_V; 5076 sprintf((char *)buf + 1, "%ld", reglen + 1); 5077 break; 5078 } 5079 rettv->v_type = VAR_STRING; 5080 rettv->vval.v_string = vim_strsave(buf); 5081 } 5082 5083 #ifdef FEAT_WINDOWS 5084 /* 5085 * Returns information (variables, options, etc.) about a tab page 5086 * as a dictionary. 5087 */ 5088 static dict_T * 5089 get_tabpage_info(tabpage_T *tp, int tp_idx) 5090 { 5091 win_T *wp; 5092 dict_T *dict; 5093 list_T *l; 5094 5095 dict = dict_alloc(); 5096 if (dict == NULL) 5097 return NULL; 5098 5099 dict_add_nr_str(dict, "tabnr", tp_idx, NULL); 5100 5101 l = list_alloc(); 5102 if (l != NULL) 5103 { 5104 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin; 5105 wp; wp = wp->w_next) 5106 list_append_number(l, (varnumber_T)wp->w_id); 5107 dict_add_list(dict, "windows", l); 5108 } 5109 5110 /* Make a reference to tabpage variables */ 5111 dict_add_dict(dict, "variables", tp->tp_vars); 5112 5113 return dict; 5114 } 5115 #endif 5116 5117 /* 5118 * "gettabinfo()" function 5119 */ 5120 static void 5121 f_gettabinfo(typval_T *argvars, typval_T *rettv) 5122 { 5123 #ifdef FEAT_WINDOWS 5124 tabpage_T *tp, *tparg = NULL; 5125 dict_T *d; 5126 int tpnr = 0; 5127 5128 if (rettv_list_alloc(rettv) != OK) 5129 return; 5130 5131 if (argvars[0].v_type != VAR_UNKNOWN) 5132 { 5133 /* Information about one tab page */ 5134 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); 5135 if (tparg == NULL) 5136 return; 5137 } 5138 5139 /* Get information about a specific tab page or all tab pages */ 5140 FOR_ALL_TABPAGES(tp) 5141 { 5142 tpnr++; 5143 if (tparg != NULL && tp != tparg) 5144 continue; 5145 d = get_tabpage_info(tp, tpnr); 5146 if (d != NULL) 5147 list_append_dict(rettv->vval.v_list, d); 5148 if (tparg != NULL) 5149 return; 5150 } 5151 #endif 5152 } 5153 5154 /* 5155 * "gettabvar()" function 5156 */ 5157 static void 5158 f_gettabvar(typval_T *argvars, typval_T *rettv) 5159 { 5160 win_T *oldcurwin; 5161 tabpage_T *tp, *oldtabpage; 5162 dictitem_T *v; 5163 char_u *varname; 5164 int done = FALSE; 5165 5166 rettv->v_type = VAR_STRING; 5167 rettv->vval.v_string = NULL; 5168 5169 varname = get_tv_string_chk(&argvars[1]); 5170 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); 5171 if (tp != NULL && varname != NULL) 5172 { 5173 /* Set tp to be our tabpage, temporarily. Also set the window to the 5174 * first window in the tabpage, otherwise the window is not valid. */ 5175 if (switch_win(&oldcurwin, &oldtabpage, 5176 tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin, tp, TRUE) 5177 == OK) 5178 { 5179 /* look up the variable */ 5180 /* Let gettabvar({nr}, "") return the "t:" dictionary. */ 5181 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE); 5182 if (v != NULL) 5183 { 5184 copy_tv(&v->di_tv, rettv); 5185 done = TRUE; 5186 } 5187 } 5188 5189 /* restore previous notion of curwin */ 5190 restore_win(oldcurwin, oldtabpage, TRUE); 5191 } 5192 5193 if (!done && argvars[2].v_type != VAR_UNKNOWN) 5194 copy_tv(&argvars[2], rettv); 5195 } 5196 5197 /* 5198 * "gettabwinvar()" function 5199 */ 5200 static void 5201 f_gettabwinvar(typval_T *argvars, typval_T *rettv) 5202 { 5203 getwinvar(argvars, rettv, 1); 5204 } 5205 5206 #ifdef FEAT_WINDOWS 5207 /* 5208 * Returns information about a window as a dictionary. 5209 */ 5210 static dict_T * 5211 get_win_info(win_T *wp, short tpnr, short winnr) 5212 { 5213 dict_T *dict; 5214 5215 dict = dict_alloc(); 5216 if (dict == NULL) 5217 return NULL; 5218 5219 dict_add_nr_str(dict, "tabnr", tpnr, NULL); 5220 dict_add_nr_str(dict, "winnr", winnr, NULL); 5221 dict_add_nr_str(dict, "winid", wp->w_id, NULL); 5222 dict_add_nr_str(dict, "height", wp->w_height, NULL); 5223 dict_add_nr_str(dict, "width", wp->w_width, NULL); 5224 dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL); 5225 5226 #ifdef FEAT_QUICKFIX 5227 dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL); 5228 dict_add_nr_str(dict, "loclist", 5229 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL); 5230 #endif 5231 5232 /* Add a reference to window variables */ 5233 dict_add_dict(dict, "variables", wp->w_vars); 5234 5235 return dict; 5236 } 5237 #endif 5238 5239 /* 5240 * "getwininfo()" function 5241 */ 5242 static void 5243 f_getwininfo(typval_T *argvars, typval_T *rettv) 5244 { 5245 #ifdef FEAT_WINDOWS 5246 tabpage_T *tp; 5247 win_T *wp = NULL, *wparg = NULL; 5248 dict_T *d; 5249 short tabnr = 0, winnr; 5250 #endif 5251 5252 if (rettv_list_alloc(rettv) != OK) 5253 return; 5254 5255 #ifdef FEAT_WINDOWS 5256 if (argvars[0].v_type != VAR_UNKNOWN) 5257 { 5258 wparg = win_id2wp(argvars); 5259 if (wparg == NULL) 5260 return; 5261 } 5262 5263 /* Collect information about either all the windows across all the tab 5264 * pages or one particular window. 5265 */ 5266 FOR_ALL_TABPAGES(tp) 5267 { 5268 tabnr++; 5269 winnr = 0; 5270 FOR_ALL_WINDOWS_IN_TAB(tp, wp) 5271 { 5272 winnr++; 5273 if (wparg != NULL && wp != wparg) 5274 continue; 5275 d = get_win_info(wp, tabnr, winnr); 5276 if (d != NULL) 5277 list_append_dict(rettv->vval.v_list, d); 5278 if (wparg != NULL) 5279 /* found information about a specific window */ 5280 return; 5281 } 5282 } 5283 #endif 5284 } 5285 5286 /* 5287 * "win_findbuf()" function 5288 */ 5289 static void 5290 f_win_findbuf(typval_T *argvars, typval_T *rettv) 5291 { 5292 if (rettv_list_alloc(rettv) != FAIL) 5293 win_findbuf(argvars, rettv->vval.v_list); 5294 } 5295 5296 /* 5297 * "win_getid()" function 5298 */ 5299 static void 5300 f_win_getid(typval_T *argvars, typval_T *rettv) 5301 { 5302 rettv->vval.v_number = win_getid(argvars); 5303 } 5304 5305 /* 5306 * "win_gotoid()" function 5307 */ 5308 static void 5309 f_win_gotoid(typval_T *argvars, typval_T *rettv) 5310 { 5311 rettv->vval.v_number = win_gotoid(argvars); 5312 } 5313 5314 /* 5315 * "win_id2tabwin()" function 5316 */ 5317 static void 5318 f_win_id2tabwin(typval_T *argvars, typval_T *rettv) 5319 { 5320 if (rettv_list_alloc(rettv) != FAIL) 5321 win_id2tabwin(argvars, rettv->vval.v_list); 5322 } 5323 5324 /* 5325 * "win_id2win()" function 5326 */ 5327 static void 5328 f_win_id2win(typval_T *argvars, typval_T *rettv) 5329 { 5330 rettv->vval.v_number = win_id2win(argvars); 5331 } 5332 5333 /* 5334 * "getwinposx()" function 5335 */ 5336 static void 5337 f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv) 5338 { 5339 rettv->vval.v_number = -1; 5340 #ifdef FEAT_GUI 5341 if (gui.in_use) 5342 { 5343 int x, y; 5344 5345 if (gui_mch_get_winpos(&x, &y) == OK) 5346 rettv->vval.v_number = x; 5347 return; 5348 } 5349 #endif 5350 #if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE) 5351 { 5352 int x, y; 5353 5354 if (term_get_winpos(&x, &y) == OK) 5355 rettv->vval.v_number = x; 5356 } 5357 #endif 5358 } 5359 5360 /* 5361 * "getwinposy()" function 5362 */ 5363 static void 5364 f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv) 5365 { 5366 rettv->vval.v_number = -1; 5367 #ifdef FEAT_GUI 5368 if (gui.in_use) 5369 { 5370 int x, y; 5371 5372 if (gui_mch_get_winpos(&x, &y) == OK) 5373 rettv->vval.v_number = y; 5374 return; 5375 } 5376 #endif 5377 #if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE) 5378 { 5379 int x, y; 5380 5381 if (term_get_winpos(&x, &y) == OK) 5382 rettv->vval.v_number = y; 5383 } 5384 #endif 5385 } 5386 5387 /* 5388 * "getwinvar()" function 5389 */ 5390 static void 5391 f_getwinvar(typval_T *argvars, typval_T *rettv) 5392 { 5393 getwinvar(argvars, rettv, 0); 5394 } 5395 5396 /* 5397 * "glob()" function 5398 */ 5399 static void 5400 f_glob(typval_T *argvars, typval_T *rettv) 5401 { 5402 int options = WILD_SILENT|WILD_USE_NL; 5403 expand_T xpc; 5404 int error = FALSE; 5405 5406 /* When the optional second argument is non-zero, don't remove matches 5407 * for 'wildignore' and don't put matches for 'suffixes' at the end. */ 5408 rettv->v_type = VAR_STRING; 5409 if (argvars[1].v_type != VAR_UNKNOWN) 5410 { 5411 if (get_tv_number_chk(&argvars[1], &error)) 5412 options |= WILD_KEEP_ALL; 5413 if (argvars[2].v_type != VAR_UNKNOWN) 5414 { 5415 if (get_tv_number_chk(&argvars[2], &error)) 5416 { 5417 rettv_list_set(rettv, NULL); 5418 } 5419 if (argvars[3].v_type != VAR_UNKNOWN 5420 && get_tv_number_chk(&argvars[3], &error)) 5421 options |= WILD_ALLLINKS; 5422 } 5423 } 5424 if (!error) 5425 { 5426 ExpandInit(&xpc); 5427 xpc.xp_context = EXPAND_FILES; 5428 if (p_wic) 5429 options += WILD_ICASE; 5430 if (rettv->v_type == VAR_STRING) 5431 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]), 5432 NULL, options, WILD_ALL); 5433 else if (rettv_list_alloc(rettv) != FAIL) 5434 { 5435 int i; 5436 5437 ExpandOne(&xpc, get_tv_string(&argvars[0]), 5438 NULL, options, WILD_ALL_KEEP); 5439 for (i = 0; i < xpc.xp_numfiles; i++) 5440 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); 5441 5442 ExpandCleanup(&xpc); 5443 } 5444 } 5445 else 5446 rettv->vval.v_string = NULL; 5447 } 5448 5449 /* 5450 * "globpath()" function 5451 */ 5452 static void 5453 f_globpath(typval_T *argvars, typval_T *rettv) 5454 { 5455 int flags = 0; 5456 char_u buf1[NUMBUFLEN]; 5457 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1); 5458 int error = FALSE; 5459 garray_T ga; 5460 int i; 5461 5462 /* When the optional second argument is non-zero, don't remove matches 5463 * for 'wildignore' and don't put matches for 'suffixes' at the end. */ 5464 rettv->v_type = VAR_STRING; 5465 if (argvars[2].v_type != VAR_UNKNOWN) 5466 { 5467 if (get_tv_number_chk(&argvars[2], &error)) 5468 flags |= WILD_KEEP_ALL; 5469 if (argvars[3].v_type != VAR_UNKNOWN) 5470 { 5471 if (get_tv_number_chk(&argvars[3], &error)) 5472 { 5473 rettv_list_set(rettv, NULL); 5474 } 5475 if (argvars[4].v_type != VAR_UNKNOWN 5476 && get_tv_number_chk(&argvars[4], &error)) 5477 flags |= WILD_ALLLINKS; 5478 } 5479 } 5480 if (file != NULL && !error) 5481 { 5482 ga_init2(&ga, (int)sizeof(char_u *), 10); 5483 globpath(get_tv_string(&argvars[0]), file, &ga, flags); 5484 if (rettv->v_type == VAR_STRING) 5485 rettv->vval.v_string = ga_concat_strings(&ga, "\n"); 5486 else if (rettv_list_alloc(rettv) != FAIL) 5487 for (i = 0; i < ga.ga_len; ++i) 5488 list_append_string(rettv->vval.v_list, 5489 ((char_u **)(ga.ga_data))[i], -1); 5490 ga_clear_strings(&ga); 5491 } 5492 else 5493 rettv->vval.v_string = NULL; 5494 } 5495 5496 /* 5497 * "glob2regpat()" function 5498 */ 5499 static void 5500 f_glob2regpat(typval_T *argvars, typval_T *rettv) 5501 { 5502 char_u *pat = get_tv_string_chk(&argvars[0]); 5503 5504 rettv->v_type = VAR_STRING; 5505 rettv->vval.v_string = (pat == NULL) 5506 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE); 5507 } 5508 5509 /* for VIM_VERSION_ defines */ 5510 #include "version.h" 5511 5512 /* 5513 * "has()" function 5514 */ 5515 static void 5516 f_has(typval_T *argvars, typval_T *rettv) 5517 { 5518 int i; 5519 char_u *name; 5520 int n = FALSE; 5521 static char *(has_list[]) = 5522 { 5523 #ifdef AMIGA 5524 "amiga", 5525 # ifdef FEAT_ARP 5526 "arp", 5527 # endif 5528 #endif 5529 #ifdef __BEOS__ 5530 "beos", 5531 #endif 5532 #ifdef MACOS 5533 "mac", 5534 #endif 5535 #if defined(MACOS_X_UNIX) 5536 "macunix", /* built with 'darwin' enabled */ 5537 #endif 5538 #if defined(__APPLE__) && __APPLE__ == 1 5539 "osx", /* built with or without 'darwin' enabled */ 5540 #endif 5541 #ifdef __QNX__ 5542 "qnx", 5543 #endif 5544 #ifdef UNIX 5545 "unix", 5546 #endif 5547 #ifdef VMS 5548 "vms", 5549 #endif 5550 #ifdef WIN32 5551 "win32", 5552 #endif 5553 #if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__)) 5554 "win32unix", 5555 #endif 5556 #if defined(WIN64) || defined(_WIN64) 5557 "win64", 5558 #endif 5559 #ifdef EBCDIC 5560 "ebcdic", 5561 #endif 5562 #ifndef CASE_INSENSITIVE_FILENAME 5563 "fname_case", 5564 #endif 5565 #ifdef HAVE_ACL 5566 "acl", 5567 #endif 5568 #ifdef FEAT_ARABIC 5569 "arabic", 5570 #endif 5571 #ifdef FEAT_AUTOCMD 5572 "autocmd", 5573 #endif 5574 #ifdef FEAT_BEVAL 5575 "balloon_eval", 5576 # ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */ 5577 "balloon_multiline", 5578 # endif 5579 #endif 5580 #if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS) 5581 "builtin_terms", 5582 # ifdef ALL_BUILTIN_TCAPS 5583 "all_builtin_terms", 5584 # endif 5585 #endif 5586 #if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \ 5587 || defined(FEAT_GUI_W32) \ 5588 || defined(FEAT_GUI_MOTIF)) 5589 "browsefilter", 5590 #endif 5591 #ifdef FEAT_BYTEOFF 5592 "byte_offset", 5593 #endif 5594 #ifdef FEAT_JOB_CHANNEL 5595 "channel", 5596 #endif 5597 #ifdef FEAT_CINDENT 5598 "cindent", 5599 #endif 5600 #ifdef FEAT_CLIENTSERVER 5601 "clientserver", 5602 #endif 5603 #ifdef FEAT_CLIPBOARD 5604 "clipboard", 5605 #endif 5606 #ifdef FEAT_CMDL_COMPL 5607 "cmdline_compl", 5608 #endif 5609 #ifdef FEAT_CMDHIST 5610 "cmdline_hist", 5611 #endif 5612 #ifdef FEAT_COMMENTS 5613 "comments", 5614 #endif 5615 #ifdef FEAT_CONCEAL 5616 "conceal", 5617 #endif 5618 #ifdef FEAT_CRYPT 5619 "cryptv", 5620 "crypt-blowfish", 5621 "crypt-blowfish2", 5622 #endif 5623 #ifdef FEAT_CSCOPE 5624 "cscope", 5625 #endif 5626 #ifdef FEAT_CURSORBIND 5627 "cursorbind", 5628 #endif 5629 #ifdef CURSOR_SHAPE 5630 "cursorshape", 5631 #endif 5632 #ifdef DEBUG 5633 "debug", 5634 #endif 5635 #ifdef FEAT_CON_DIALOG 5636 "dialog_con", 5637 #endif 5638 #ifdef FEAT_GUI_DIALOG 5639 "dialog_gui", 5640 #endif 5641 #ifdef FEAT_DIFF 5642 "diff", 5643 #endif 5644 #ifdef FEAT_DIGRAPHS 5645 "digraphs", 5646 #endif 5647 #ifdef FEAT_DIRECTX 5648 "directx", 5649 #endif 5650 #ifdef FEAT_DND 5651 "dnd", 5652 #endif 5653 #ifdef FEAT_EMACS_TAGS 5654 "emacs_tags", 5655 #endif 5656 "eval", /* always present, of course! */ 5657 "ex_extra", /* graduated feature */ 5658 #ifdef FEAT_SEARCH_EXTRA 5659 "extra_search", 5660 #endif 5661 #ifdef FEAT_FKMAP 5662 "farsi", 5663 #endif 5664 #ifdef FEAT_SEARCHPATH 5665 "file_in_path", 5666 #endif 5667 #ifdef FEAT_FILTERPIPE 5668 "filterpipe", 5669 #endif 5670 #ifdef FEAT_FIND_ID 5671 "find_in_path", 5672 #endif 5673 #ifdef FEAT_FLOAT 5674 "float", 5675 #endif 5676 #ifdef FEAT_FOLDING 5677 "folding", 5678 #endif 5679 #ifdef FEAT_FOOTER 5680 "footer", 5681 #endif 5682 #if !defined(USE_SYSTEM) && defined(UNIX) 5683 "fork", 5684 #endif 5685 #ifdef FEAT_GETTEXT 5686 "gettext", 5687 #endif 5688 #ifdef FEAT_GUI 5689 "gui", 5690 #endif 5691 #ifdef FEAT_GUI_ATHENA 5692 # ifdef FEAT_GUI_NEXTAW 5693 "gui_neXtaw", 5694 # else 5695 "gui_athena", 5696 # endif 5697 #endif 5698 #ifdef FEAT_GUI_GTK 5699 "gui_gtk", 5700 # ifdef USE_GTK3 5701 "gui_gtk3", 5702 # else 5703 "gui_gtk2", 5704 # endif 5705 #endif 5706 #ifdef FEAT_GUI_GNOME 5707 "gui_gnome", 5708 #endif 5709 #ifdef FEAT_GUI_MAC 5710 "gui_mac", 5711 #endif 5712 #ifdef FEAT_GUI_MOTIF 5713 "gui_motif", 5714 #endif 5715 #ifdef FEAT_GUI_PHOTON 5716 "gui_photon", 5717 #endif 5718 #ifdef FEAT_GUI_W32 5719 "gui_win32", 5720 #endif 5721 #ifdef FEAT_HANGULIN 5722 "hangul_input", 5723 #endif 5724 #if defined(HAVE_ICONV_H) && defined(USE_ICONV) 5725 "iconv", 5726 #endif 5727 #ifdef FEAT_INS_EXPAND 5728 "insert_expand", 5729 #endif 5730 #ifdef FEAT_JOB_CHANNEL 5731 "job", 5732 #endif 5733 #ifdef FEAT_JUMPLIST 5734 "jumplist", 5735 #endif 5736 #ifdef FEAT_KEYMAP 5737 "keymap", 5738 #endif 5739 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */ 5740 #ifdef FEAT_LANGMAP 5741 "langmap", 5742 #endif 5743 #ifdef FEAT_LIBCALL 5744 "libcall", 5745 #endif 5746 #ifdef FEAT_LINEBREAK 5747 "linebreak", 5748 #endif 5749 #ifdef FEAT_LISP 5750 "lispindent", 5751 #endif 5752 #ifdef FEAT_LISTCMDS 5753 "listcmds", 5754 #endif 5755 #ifdef FEAT_LOCALMAP 5756 "localmap", 5757 #endif 5758 #ifdef FEAT_LUA 5759 # ifndef DYNAMIC_LUA 5760 "lua", 5761 # endif 5762 #endif 5763 #ifdef FEAT_MENU 5764 "menu", 5765 #endif 5766 #ifdef FEAT_SESSION 5767 "mksession", 5768 #endif 5769 #ifdef FEAT_MODIFY_FNAME 5770 "modify_fname", 5771 #endif 5772 #ifdef FEAT_MOUSE 5773 "mouse", 5774 #endif 5775 #ifdef FEAT_MOUSESHAPE 5776 "mouseshape", 5777 #endif 5778 #if defined(UNIX) || defined(VMS) 5779 # ifdef FEAT_MOUSE_DEC 5780 "mouse_dec", 5781 # endif 5782 # ifdef FEAT_MOUSE_GPM 5783 "mouse_gpm", 5784 # endif 5785 # ifdef FEAT_MOUSE_JSB 5786 "mouse_jsbterm", 5787 # endif 5788 # ifdef FEAT_MOUSE_NET 5789 "mouse_netterm", 5790 # endif 5791 # ifdef FEAT_MOUSE_PTERM 5792 "mouse_pterm", 5793 # endif 5794 # ifdef FEAT_MOUSE_SGR 5795 "mouse_sgr", 5796 # endif 5797 # ifdef FEAT_SYSMOUSE 5798 "mouse_sysmouse", 5799 # endif 5800 # ifdef FEAT_MOUSE_URXVT 5801 "mouse_urxvt", 5802 # endif 5803 # ifdef FEAT_MOUSE_XTERM 5804 "mouse_xterm", 5805 # endif 5806 #endif 5807 #ifdef FEAT_MBYTE 5808 "multi_byte", 5809 #endif 5810 #ifdef FEAT_MBYTE_IME 5811 "multi_byte_ime", 5812 #endif 5813 #ifdef FEAT_MULTI_LANG 5814 "multi_lang", 5815 #endif 5816 #ifdef FEAT_MZSCHEME 5817 #ifndef DYNAMIC_MZSCHEME 5818 "mzscheme", 5819 #endif 5820 #endif 5821 #ifdef FEAT_NUM64 5822 "num64", 5823 #endif 5824 #ifdef FEAT_OLE 5825 "ole", 5826 #endif 5827 "packages", 5828 #ifdef FEAT_PATH_EXTRA 5829 "path_extra", 5830 #endif 5831 #ifdef FEAT_PERL 5832 #ifndef DYNAMIC_PERL 5833 "perl", 5834 #endif 5835 #endif 5836 #ifdef FEAT_PERSISTENT_UNDO 5837 "persistent_undo", 5838 #endif 5839 #if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON) 5840 "python", 5841 "pythonx", 5842 #endif 5843 #if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3) 5844 "python3", 5845 "pythonx", 5846 #endif 5847 #ifdef FEAT_POSTSCRIPT 5848 "postscript", 5849 #endif 5850 #ifdef FEAT_PRINTER 5851 "printer", 5852 #endif 5853 #ifdef FEAT_PROFILE 5854 "profile", 5855 #endif 5856 #ifdef FEAT_RELTIME 5857 "reltime", 5858 #endif 5859 #ifdef FEAT_QUICKFIX 5860 "quickfix", 5861 #endif 5862 #ifdef FEAT_RIGHTLEFT 5863 "rightleft", 5864 #endif 5865 #if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY) 5866 "ruby", 5867 #endif 5868 #ifdef FEAT_SCROLLBIND 5869 "scrollbind", 5870 #endif 5871 #ifdef FEAT_CMDL_INFO 5872 "showcmd", 5873 "cmdline_info", 5874 #endif 5875 #ifdef FEAT_SIGNS 5876 "signs", 5877 #endif 5878 #ifdef FEAT_SMARTINDENT 5879 "smartindent", 5880 #endif 5881 #ifdef STARTUPTIME 5882 "startuptime", 5883 #endif 5884 #ifdef FEAT_STL_OPT 5885 "statusline", 5886 #endif 5887 #ifdef FEAT_SUN_WORKSHOP 5888 "sun_workshop", 5889 #endif 5890 #ifdef FEAT_NETBEANS_INTG 5891 "netbeans_intg", 5892 #endif 5893 #ifdef FEAT_SPELL 5894 "spell", 5895 #endif 5896 #ifdef FEAT_SYN_HL 5897 "syntax", 5898 #endif 5899 #if defined(USE_SYSTEM) || !defined(UNIX) 5900 "system", 5901 #endif 5902 #ifdef FEAT_TAG_BINS 5903 "tag_binary", 5904 #endif 5905 #ifdef FEAT_TAG_OLDSTATIC 5906 "tag_old_static", 5907 #endif 5908 #ifdef FEAT_TAG_ANYWHITE 5909 "tag_any_white", 5910 #endif 5911 #ifdef FEAT_TCL 5912 # ifndef DYNAMIC_TCL 5913 "tcl", 5914 # endif 5915 #endif 5916 #ifdef FEAT_TERMGUICOLORS 5917 "termguicolors", 5918 #endif 5919 #ifdef FEAT_TERMINAL 5920 "terminal", 5921 #endif 5922 #ifdef TERMINFO 5923 "terminfo", 5924 #endif 5925 #ifdef FEAT_TERMRESPONSE 5926 "termresponse", 5927 #endif 5928 #ifdef FEAT_TEXTOBJ 5929 "textobjects", 5930 #endif 5931 #ifdef HAVE_TGETENT 5932 "tgetent", 5933 #endif 5934 #ifdef FEAT_TIMERS 5935 "timers", 5936 #endif 5937 #ifdef FEAT_TITLE 5938 "title", 5939 #endif 5940 #ifdef FEAT_TOOLBAR 5941 "toolbar", 5942 #endif 5943 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11) 5944 "unnamedplus", 5945 #endif 5946 #ifdef FEAT_USR_CMDS 5947 "user-commands", /* was accidentally included in 5.4 */ 5948 "user_commands", 5949 #endif 5950 #ifdef FEAT_VIMINFO 5951 "viminfo", 5952 #endif 5953 #ifdef FEAT_WINDOWS 5954 "vertsplit", 5955 #endif 5956 #ifdef FEAT_VIRTUALEDIT 5957 "virtualedit", 5958 #endif 5959 "visual", 5960 #ifdef FEAT_VISUALEXTRA 5961 "visualextra", 5962 #endif 5963 #ifdef FEAT_VREPLACE 5964 "vreplace", 5965 #endif 5966 #ifdef FEAT_WILDIGN 5967 "wildignore", 5968 #endif 5969 #ifdef FEAT_WILDMENU 5970 "wildmenu", 5971 #endif 5972 #ifdef FEAT_WINDOWS 5973 "windows", 5974 #endif 5975 #ifdef FEAT_WAK 5976 "winaltkeys", 5977 #endif 5978 #ifdef FEAT_WRITEBACKUP 5979 "writebackup", 5980 #endif 5981 #ifdef FEAT_XIM 5982 "xim", 5983 #endif 5984 #ifdef FEAT_XFONTSET 5985 "xfontset", 5986 #endif 5987 #ifdef FEAT_XPM_W32 5988 "xpm", 5989 "xpm_w32", /* for backward compatibility */ 5990 #else 5991 # if defined(HAVE_XPM) 5992 "xpm", 5993 # endif 5994 #endif 5995 #ifdef USE_XSMP 5996 "xsmp", 5997 #endif 5998 #ifdef USE_XSMP_INTERACT 5999 "xsmp_interact", 6000 #endif 6001 #ifdef FEAT_XCLIPBOARD 6002 "xterm_clipboard", 6003 #endif 6004 #ifdef FEAT_XTERM_SAVE 6005 "xterm_save", 6006 #endif 6007 #if defined(UNIX) && defined(FEAT_X11) 6008 "X11", 6009 #endif 6010 NULL 6011 }; 6012 6013 name = get_tv_string(&argvars[0]); 6014 for (i = 0; has_list[i] != NULL; ++i) 6015 if (STRICMP(name, has_list[i]) == 0) 6016 { 6017 n = TRUE; 6018 break; 6019 } 6020 6021 if (n == FALSE) 6022 { 6023 if (STRNICMP(name, "patch", 5) == 0) 6024 { 6025 if (name[5] == '-' 6026 && STRLEN(name) >= 11 6027 && vim_isdigit(name[6]) 6028 && vim_isdigit(name[8]) 6029 && vim_isdigit(name[10])) 6030 { 6031 int major = atoi((char *)name + 6); 6032 int minor = atoi((char *)name + 8); 6033 6034 /* Expect "patch-9.9.01234". */ 6035 n = (major < VIM_VERSION_MAJOR 6036 || (major == VIM_VERSION_MAJOR 6037 && (minor < VIM_VERSION_MINOR 6038 || (minor == VIM_VERSION_MINOR 6039 && has_patch(atoi((char *)name + 10)))))); 6040 } 6041 else 6042 n = has_patch(atoi((char *)name + 5)); 6043 } 6044 else if (STRICMP(name, "vim_starting") == 0) 6045 n = (starting != 0); 6046 else if (STRICMP(name, "ttyin") == 0) 6047 n = mch_input_isatty(); 6048 else if (STRICMP(name, "ttyout") == 0) 6049 n = stdout_isatty; 6050 #ifdef FEAT_MBYTE 6051 else if (STRICMP(name, "multi_byte_encoding") == 0) 6052 n = has_mbyte; 6053 #endif 6054 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32) 6055 else if (STRICMP(name, "balloon_multiline") == 0) 6056 n = multiline_balloon_available(); 6057 #endif 6058 #ifdef DYNAMIC_TCL 6059 else if (STRICMP(name, "tcl") == 0) 6060 n = tcl_enabled(FALSE); 6061 #endif 6062 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV) 6063 else if (STRICMP(name, "iconv") == 0) 6064 n = iconv_enabled(FALSE); 6065 #endif 6066 #ifdef DYNAMIC_LUA 6067 else if (STRICMP(name, "lua") == 0) 6068 n = lua_enabled(FALSE); 6069 #endif 6070 #ifdef DYNAMIC_MZSCHEME 6071 else if (STRICMP(name, "mzscheme") == 0) 6072 n = mzscheme_enabled(FALSE); 6073 #endif 6074 #ifdef DYNAMIC_RUBY 6075 else if (STRICMP(name, "ruby") == 0) 6076 n = ruby_enabled(FALSE); 6077 #endif 6078 #ifdef DYNAMIC_PYTHON 6079 else if (STRICMP(name, "python") == 0) 6080 n = python_enabled(FALSE); 6081 #endif 6082 #ifdef DYNAMIC_PYTHON3 6083 else if (STRICMP(name, "python3") == 0) 6084 n = python3_enabled(FALSE); 6085 #endif 6086 #if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3) 6087 else if (STRICMP(name, "pythonx") == 0) 6088 { 6089 # if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3) 6090 if (p_pyx == 0) 6091 n = python3_enabled(FALSE) || python_enabled(FALSE); 6092 else if (p_pyx == 3) 6093 n = python3_enabled(FALSE); 6094 else if (p_pyx == 2) 6095 n = python_enabled(FALSE); 6096 # elif defined(DYNAMIC_PYTHON) 6097 n = python_enabled(FALSE); 6098 # elif defined(DYNAMIC_PYTHON3) 6099 n = python3_enabled(FALSE); 6100 # endif 6101 } 6102 #endif 6103 #ifdef DYNAMIC_PERL 6104 else if (STRICMP(name, "perl") == 0) 6105 n = perl_enabled(FALSE); 6106 #endif 6107 #ifdef FEAT_GUI 6108 else if (STRICMP(name, "gui_running") == 0) 6109 n = (gui.in_use || gui.starting); 6110 # ifdef FEAT_BROWSE 6111 else if (STRICMP(name, "browse") == 0) 6112 n = gui.in_use; /* gui_mch_browse() works when GUI is running */ 6113 # endif 6114 #endif 6115 #ifdef FEAT_SYN_HL 6116 else if (STRICMP(name, "syntax_items") == 0) 6117 n = syntax_present(curwin); 6118 #endif 6119 #if defined(WIN3264) 6120 else if (STRICMP(name, "win95") == 0) 6121 n = FALSE; /* Win9x is no more supported. */ 6122 #endif 6123 #ifdef FEAT_NETBEANS_INTG 6124 else if (STRICMP(name, "netbeans_enabled") == 0) 6125 n = netbeans_active(); 6126 #endif 6127 } 6128 6129 rettv->vval.v_number = n; 6130 } 6131 6132 /* 6133 * "has_key()" function 6134 */ 6135 static void 6136 f_has_key(typval_T *argvars, typval_T *rettv) 6137 { 6138 if (argvars[0].v_type != VAR_DICT) 6139 { 6140 EMSG(_(e_dictreq)); 6141 return; 6142 } 6143 if (argvars[0].vval.v_dict == NULL) 6144 return; 6145 6146 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict, 6147 get_tv_string(&argvars[1]), -1) != NULL; 6148 } 6149 6150 /* 6151 * "haslocaldir()" function 6152 */ 6153 static void 6154 f_haslocaldir(typval_T *argvars, typval_T *rettv) 6155 { 6156 win_T *wp = NULL; 6157 6158 wp = find_tabwin(&argvars[0], &argvars[1]); 6159 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL); 6160 } 6161 6162 /* 6163 * "hasmapto()" function 6164 */ 6165 static void 6166 f_hasmapto(typval_T *argvars, typval_T *rettv) 6167 { 6168 char_u *name; 6169 char_u *mode; 6170 char_u buf[NUMBUFLEN]; 6171 int abbr = FALSE; 6172 6173 name = get_tv_string(&argvars[0]); 6174 if (argvars[1].v_type == VAR_UNKNOWN) 6175 mode = (char_u *)"nvo"; 6176 else 6177 { 6178 mode = get_tv_string_buf(&argvars[1], buf); 6179 if (argvars[2].v_type != VAR_UNKNOWN) 6180 abbr = (int)get_tv_number(&argvars[2]); 6181 } 6182 6183 if (map_to_exists(name, mode, abbr)) 6184 rettv->vval.v_number = TRUE; 6185 else 6186 rettv->vval.v_number = FALSE; 6187 } 6188 6189 /* 6190 * "histadd()" function 6191 */ 6192 static void 6193 f_histadd(typval_T *argvars UNUSED, typval_T *rettv) 6194 { 6195 #ifdef FEAT_CMDHIST 6196 int histype; 6197 char_u *str; 6198 char_u buf[NUMBUFLEN]; 6199 #endif 6200 6201 rettv->vval.v_number = FALSE; 6202 if (check_restricted() || check_secure()) 6203 return; 6204 #ifdef FEAT_CMDHIST 6205 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ 6206 histype = str != NULL ? get_histtype(str) : -1; 6207 if (histype >= 0) 6208 { 6209 str = get_tv_string_buf(&argvars[1], buf); 6210 if (*str != NUL) 6211 { 6212 init_history(); 6213 add_to_history(histype, str, FALSE, NUL); 6214 rettv->vval.v_number = TRUE; 6215 return; 6216 } 6217 } 6218 #endif 6219 } 6220 6221 /* 6222 * "histdel()" function 6223 */ 6224 static void 6225 f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 6226 { 6227 #ifdef FEAT_CMDHIST 6228 int n; 6229 char_u buf[NUMBUFLEN]; 6230 char_u *str; 6231 6232 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ 6233 if (str == NULL) 6234 n = 0; 6235 else if (argvars[1].v_type == VAR_UNKNOWN) 6236 /* only one argument: clear entire history */ 6237 n = clr_history(get_histtype(str)); 6238 else if (argvars[1].v_type == VAR_NUMBER) 6239 /* index given: remove that entry */ 6240 n = del_history_idx(get_histtype(str), 6241 (int)get_tv_number(&argvars[1])); 6242 else 6243 /* string given: remove all matching entries */ 6244 n = del_history_entry(get_histtype(str), 6245 get_tv_string_buf(&argvars[1], buf)); 6246 rettv->vval.v_number = n; 6247 #endif 6248 } 6249 6250 /* 6251 * "histget()" function 6252 */ 6253 static void 6254 f_histget(typval_T *argvars UNUSED, typval_T *rettv) 6255 { 6256 #ifdef FEAT_CMDHIST 6257 int type; 6258 int idx; 6259 char_u *str; 6260 6261 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ 6262 if (str == NULL) 6263 rettv->vval.v_string = NULL; 6264 else 6265 { 6266 type = get_histtype(str); 6267 if (argvars[1].v_type == VAR_UNKNOWN) 6268 idx = get_history_idx(type); 6269 else 6270 idx = (int)get_tv_number_chk(&argvars[1], NULL); 6271 /* -1 on type error */ 6272 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx)); 6273 } 6274 #else 6275 rettv->vval.v_string = NULL; 6276 #endif 6277 rettv->v_type = VAR_STRING; 6278 } 6279 6280 /* 6281 * "histnr()" function 6282 */ 6283 static void 6284 f_histnr(typval_T *argvars UNUSED, typval_T *rettv) 6285 { 6286 int i; 6287 6288 #ifdef FEAT_CMDHIST 6289 char_u *history = get_tv_string_chk(&argvars[0]); 6290 6291 i = history == NULL ? HIST_CMD - 1 : get_histtype(history); 6292 if (i >= HIST_CMD && i < HIST_COUNT) 6293 i = get_history_idx(i); 6294 else 6295 #endif 6296 i = -1; 6297 rettv->vval.v_number = i; 6298 } 6299 6300 /* 6301 * "highlightID(name)" function 6302 */ 6303 static void 6304 f_hlID(typval_T *argvars, typval_T *rettv) 6305 { 6306 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0])); 6307 } 6308 6309 /* 6310 * "highlight_exists()" function 6311 */ 6312 static void 6313 f_hlexists(typval_T *argvars, typval_T *rettv) 6314 { 6315 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0])); 6316 } 6317 6318 /* 6319 * "hostname()" function 6320 */ 6321 static void 6322 f_hostname(typval_T *argvars UNUSED, typval_T *rettv) 6323 { 6324 char_u hostname[256]; 6325 6326 mch_get_host_name(hostname, 256); 6327 rettv->v_type = VAR_STRING; 6328 rettv->vval.v_string = vim_strsave(hostname); 6329 } 6330 6331 /* 6332 * iconv() function 6333 */ 6334 static void 6335 f_iconv(typval_T *argvars UNUSED, typval_T *rettv) 6336 { 6337 #ifdef FEAT_MBYTE 6338 char_u buf1[NUMBUFLEN]; 6339 char_u buf2[NUMBUFLEN]; 6340 char_u *from, *to, *str; 6341 vimconv_T vimconv; 6342 #endif 6343 6344 rettv->v_type = VAR_STRING; 6345 rettv->vval.v_string = NULL; 6346 6347 #ifdef FEAT_MBYTE 6348 str = get_tv_string(&argvars[0]); 6349 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1))); 6350 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2))); 6351 vimconv.vc_type = CONV_NONE; 6352 convert_setup(&vimconv, from, to); 6353 6354 /* If the encodings are equal, no conversion needed. */ 6355 if (vimconv.vc_type == CONV_NONE) 6356 rettv->vval.v_string = vim_strsave(str); 6357 else 6358 rettv->vval.v_string = string_convert(&vimconv, str, NULL); 6359 6360 convert_setup(&vimconv, NULL, NULL); 6361 vim_free(from); 6362 vim_free(to); 6363 #endif 6364 } 6365 6366 /* 6367 * "indent()" function 6368 */ 6369 static void 6370 f_indent(typval_T *argvars, typval_T *rettv) 6371 { 6372 linenr_T lnum; 6373 6374 lnum = get_tv_lnum(argvars); 6375 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) 6376 rettv->vval.v_number = get_indent_lnum(lnum); 6377 else 6378 rettv->vval.v_number = -1; 6379 } 6380 6381 /* 6382 * "index()" function 6383 */ 6384 static void 6385 f_index(typval_T *argvars, typval_T *rettv) 6386 { 6387 list_T *l; 6388 listitem_T *item; 6389 long idx = 0; 6390 int ic = FALSE; 6391 6392 rettv->vval.v_number = -1; 6393 if (argvars[0].v_type != VAR_LIST) 6394 { 6395 EMSG(_(e_listreq)); 6396 return; 6397 } 6398 l = argvars[0].vval.v_list; 6399 if (l != NULL) 6400 { 6401 item = l->lv_first; 6402 if (argvars[2].v_type != VAR_UNKNOWN) 6403 { 6404 int error = FALSE; 6405 6406 /* Start at specified item. Use the cached index that list_find() 6407 * sets, so that a negative number also works. */ 6408 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error)); 6409 idx = l->lv_idx; 6410 if (argvars[3].v_type != VAR_UNKNOWN) 6411 ic = (int)get_tv_number_chk(&argvars[3], &error); 6412 if (error) 6413 item = NULL; 6414 } 6415 6416 for ( ; item != NULL; item = item->li_next, ++idx) 6417 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE)) 6418 { 6419 rettv->vval.v_number = idx; 6420 break; 6421 } 6422 } 6423 } 6424 6425 static int inputsecret_flag = 0; 6426 6427 /* 6428 * "input()" function 6429 * Also handles inputsecret() when inputsecret is set. 6430 */ 6431 static void 6432 f_input(typval_T *argvars, typval_T *rettv) 6433 { 6434 get_user_input(argvars, rettv, FALSE, inputsecret_flag); 6435 } 6436 6437 /* 6438 * "inputdialog()" function 6439 */ 6440 static void 6441 f_inputdialog(typval_T *argvars, typval_T *rettv) 6442 { 6443 #if defined(FEAT_GUI_TEXTDIALOG) 6444 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */ 6445 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL) 6446 { 6447 char_u *message; 6448 char_u buf[NUMBUFLEN]; 6449 char_u *defstr = (char_u *)""; 6450 6451 message = get_tv_string_chk(&argvars[0]); 6452 if (argvars[1].v_type != VAR_UNKNOWN 6453 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL) 6454 vim_strncpy(IObuff, defstr, IOSIZE - 1); 6455 else 6456 IObuff[0] = NUL; 6457 if (message != NULL && defstr != NULL 6458 && do_dialog(VIM_QUESTION, NULL, message, 6459 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1) 6460 rettv->vval.v_string = vim_strsave(IObuff); 6461 else 6462 { 6463 if (message != NULL && defstr != NULL 6464 && argvars[1].v_type != VAR_UNKNOWN 6465 && argvars[2].v_type != VAR_UNKNOWN) 6466 rettv->vval.v_string = vim_strsave( 6467 get_tv_string_buf(&argvars[2], buf)); 6468 else 6469 rettv->vval.v_string = NULL; 6470 } 6471 rettv->v_type = VAR_STRING; 6472 } 6473 else 6474 #endif 6475 get_user_input(argvars, rettv, TRUE, inputsecret_flag); 6476 } 6477 6478 /* 6479 * "inputlist()" function 6480 */ 6481 static void 6482 f_inputlist(typval_T *argvars, typval_T *rettv) 6483 { 6484 listitem_T *li; 6485 int selected; 6486 int mouse_used; 6487 6488 #ifdef NO_CONSOLE_INPUT 6489 /* While starting up, there is no place to enter text. When running tests 6490 * with --not-a-term we assume feedkeys() will be used. */ 6491 if (no_console_input() && !is_not_a_term()) 6492 return; 6493 #endif 6494 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL) 6495 { 6496 EMSG2(_(e_listarg), "inputlist()"); 6497 return; 6498 } 6499 6500 msg_start(); 6501 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */ 6502 lines_left = Rows; /* avoid more prompt */ 6503 msg_scroll = TRUE; 6504 msg_clr_eos(); 6505 6506 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next) 6507 { 6508 msg_puts(get_tv_string(&li->li_tv)); 6509 msg_putchar('\n'); 6510 } 6511 6512 /* Ask for choice. */ 6513 selected = prompt_for_number(&mouse_used); 6514 if (mouse_used) 6515 selected -= lines_left; 6516 6517 rettv->vval.v_number = selected; 6518 } 6519 6520 6521 static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL}; 6522 6523 /* 6524 * "inputrestore()" function 6525 */ 6526 static void 6527 f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv) 6528 { 6529 if (ga_userinput.ga_len > 0) 6530 { 6531 --ga_userinput.ga_len; 6532 restore_typeahead((tasave_T *)(ga_userinput.ga_data) 6533 + ga_userinput.ga_len); 6534 /* default return is zero == OK */ 6535 } 6536 else if (p_verbose > 1) 6537 { 6538 verb_msg((char_u *)_("called inputrestore() more often than inputsave()")); 6539 rettv->vval.v_number = 1; /* Failed */ 6540 } 6541 } 6542 6543 /* 6544 * "inputsave()" function 6545 */ 6546 static void 6547 f_inputsave(typval_T *argvars UNUSED, typval_T *rettv) 6548 { 6549 /* Add an entry to the stack of typeahead storage. */ 6550 if (ga_grow(&ga_userinput, 1) == OK) 6551 { 6552 save_typeahead((tasave_T *)(ga_userinput.ga_data) 6553 + ga_userinput.ga_len); 6554 ++ga_userinput.ga_len; 6555 /* default return is zero == OK */ 6556 } 6557 else 6558 rettv->vval.v_number = 1; /* Failed */ 6559 } 6560 6561 /* 6562 * "inputsecret()" function 6563 */ 6564 static void 6565 f_inputsecret(typval_T *argvars, typval_T *rettv) 6566 { 6567 ++cmdline_star; 6568 ++inputsecret_flag; 6569 f_input(argvars, rettv); 6570 --cmdline_star; 6571 --inputsecret_flag; 6572 } 6573 6574 /* 6575 * "insert()" function 6576 */ 6577 static void 6578 f_insert(typval_T *argvars, typval_T *rettv) 6579 { 6580 long before = 0; 6581 listitem_T *item; 6582 list_T *l; 6583 int error = FALSE; 6584 6585 if (argvars[0].v_type != VAR_LIST) 6586 EMSG2(_(e_listarg), "insert()"); 6587 else if ((l = argvars[0].vval.v_list) != NULL 6588 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE)) 6589 { 6590 if (argvars[2].v_type != VAR_UNKNOWN) 6591 before = (long)get_tv_number_chk(&argvars[2], &error); 6592 if (error) 6593 return; /* type error; errmsg already given */ 6594 6595 if (before == l->lv_len) 6596 item = NULL; 6597 else 6598 { 6599 item = list_find(l, before); 6600 if (item == NULL) 6601 { 6602 EMSGN(_(e_listidx), before); 6603 l = NULL; 6604 } 6605 } 6606 if (l != NULL) 6607 { 6608 list_insert_tv(l, &argvars[1], item); 6609 copy_tv(&argvars[0], rettv); 6610 } 6611 } 6612 } 6613 6614 /* 6615 * "invert(expr)" function 6616 */ 6617 static void 6618 f_invert(typval_T *argvars, typval_T *rettv) 6619 { 6620 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL); 6621 } 6622 6623 /* 6624 * "isdirectory()" function 6625 */ 6626 static void 6627 f_isdirectory(typval_T *argvars, typval_T *rettv) 6628 { 6629 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0])); 6630 } 6631 6632 /* 6633 * Return TRUE if typeval "tv" is locked: Either that value is locked itself 6634 * or it refers to a List or Dictionary that is locked. 6635 */ 6636 static int 6637 tv_islocked(typval_T *tv) 6638 { 6639 return (tv->v_lock & VAR_LOCKED) 6640 || (tv->v_type == VAR_LIST 6641 && tv->vval.v_list != NULL 6642 && (tv->vval.v_list->lv_lock & VAR_LOCKED)) 6643 || (tv->v_type == VAR_DICT 6644 && tv->vval.v_dict != NULL 6645 && (tv->vval.v_dict->dv_lock & VAR_LOCKED)); 6646 } 6647 6648 /* 6649 * "islocked()" function 6650 */ 6651 static void 6652 f_islocked(typval_T *argvars, typval_T *rettv) 6653 { 6654 lval_T lv; 6655 char_u *end; 6656 dictitem_T *di; 6657 6658 rettv->vval.v_number = -1; 6659 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE, 6660 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START); 6661 if (end != NULL && lv.ll_name != NULL) 6662 { 6663 if (*end != NUL) 6664 EMSG(_(e_trailing)); 6665 else 6666 { 6667 if (lv.ll_tv == NULL) 6668 { 6669 di = find_var(lv.ll_name, NULL, TRUE); 6670 if (di != NULL) 6671 { 6672 /* Consider a variable locked when: 6673 * 1. the variable itself is locked 6674 * 2. the value of the variable is locked. 6675 * 3. the List or Dict value is locked. 6676 */ 6677 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK) 6678 || tv_islocked(&di->di_tv)); 6679 } 6680 } 6681 else if (lv.ll_range) 6682 EMSG(_("E786: Range not allowed")); 6683 else if (lv.ll_newkey != NULL) 6684 EMSG2(_(e_dictkey), lv.ll_newkey); 6685 else if (lv.ll_list != NULL) 6686 /* List item. */ 6687 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv); 6688 else 6689 /* Dictionary item. */ 6690 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv); 6691 } 6692 } 6693 6694 clear_lval(&lv); 6695 } 6696 6697 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) 6698 /* 6699 * "isnan()" function 6700 */ 6701 static void 6702 f_isnan(typval_T *argvars, typval_T *rettv) 6703 { 6704 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT 6705 && isnan(argvars[0].vval.v_float); 6706 } 6707 #endif 6708 6709 /* 6710 * "items(dict)" function 6711 */ 6712 static void 6713 f_items(typval_T *argvars, typval_T *rettv) 6714 { 6715 dict_list(argvars, rettv, 2); 6716 } 6717 6718 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) 6719 /* 6720 * Get the job from the argument. 6721 * Returns NULL if the job is invalid. 6722 */ 6723 static job_T * 6724 get_job_arg(typval_T *tv) 6725 { 6726 job_T *job; 6727 6728 if (tv->v_type != VAR_JOB) 6729 { 6730 EMSG2(_(e_invarg2), get_tv_string(tv)); 6731 return NULL; 6732 } 6733 job = tv->vval.v_job; 6734 6735 if (job == NULL) 6736 EMSG(_("E916: not a valid job")); 6737 return job; 6738 } 6739 6740 /* 6741 * "job_getchannel()" function 6742 */ 6743 static void 6744 f_job_getchannel(typval_T *argvars, typval_T *rettv) 6745 { 6746 job_T *job = get_job_arg(&argvars[0]); 6747 6748 if (job != NULL) 6749 { 6750 rettv->v_type = VAR_CHANNEL; 6751 rettv->vval.v_channel = job->jv_channel; 6752 if (job->jv_channel != NULL) 6753 ++job->jv_channel->ch_refcount; 6754 } 6755 } 6756 6757 /* 6758 * "job_info()" function 6759 */ 6760 static void 6761 f_job_info(typval_T *argvars, typval_T *rettv) 6762 { 6763 job_T *job = get_job_arg(&argvars[0]); 6764 6765 if (job != NULL && rettv_dict_alloc(rettv) != FAIL) 6766 job_info(job, rettv->vval.v_dict); 6767 } 6768 6769 /* 6770 * "job_setoptions()" function 6771 */ 6772 static void 6773 f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED) 6774 { 6775 job_T *job = get_job_arg(&argvars[0]); 6776 jobopt_T opt; 6777 6778 if (job == NULL) 6779 return; 6780 clear_job_options(&opt); 6781 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB) == OK) 6782 job_set_options(job, &opt); 6783 free_job_options(&opt); 6784 } 6785 6786 /* 6787 * "job_start()" function 6788 */ 6789 static void 6790 f_job_start(typval_T *argvars, typval_T *rettv) 6791 { 6792 rettv->v_type = VAR_JOB; 6793 if (check_restricted() || check_secure()) 6794 return; 6795 rettv->vval.v_job = job_start(argvars, NULL); 6796 } 6797 6798 /* 6799 * "job_status()" function 6800 */ 6801 static void 6802 f_job_status(typval_T *argvars, typval_T *rettv) 6803 { 6804 job_T *job = get_job_arg(&argvars[0]); 6805 6806 if (job != NULL) 6807 { 6808 rettv->v_type = VAR_STRING; 6809 rettv->vval.v_string = vim_strsave((char_u *)job_status(job)); 6810 } 6811 } 6812 6813 /* 6814 * "job_stop()" function 6815 */ 6816 static void 6817 f_job_stop(typval_T *argvars, typval_T *rettv) 6818 { 6819 job_T *job = get_job_arg(&argvars[0]); 6820 6821 if (job != NULL) 6822 rettv->vval.v_number = job_stop(job, argvars, NULL); 6823 } 6824 #endif 6825 6826 /* 6827 * "join()" function 6828 */ 6829 static void 6830 f_join(typval_T *argvars, typval_T *rettv) 6831 { 6832 garray_T ga; 6833 char_u *sep; 6834 6835 if (argvars[0].v_type != VAR_LIST) 6836 { 6837 EMSG(_(e_listreq)); 6838 return; 6839 } 6840 if (argvars[0].vval.v_list == NULL) 6841 return; 6842 if (argvars[1].v_type == VAR_UNKNOWN) 6843 sep = (char_u *)" "; 6844 else 6845 sep = get_tv_string_chk(&argvars[1]); 6846 6847 rettv->v_type = VAR_STRING; 6848 6849 if (sep != NULL) 6850 { 6851 ga_init2(&ga, (int)sizeof(char), 80); 6852 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0); 6853 ga_append(&ga, NUL); 6854 rettv->vval.v_string = (char_u *)ga.ga_data; 6855 } 6856 else 6857 rettv->vval.v_string = NULL; 6858 } 6859 6860 /* 6861 * "js_decode()" function 6862 */ 6863 static void 6864 f_js_decode(typval_T *argvars, typval_T *rettv) 6865 { 6866 js_read_T reader; 6867 6868 reader.js_buf = get_tv_string(&argvars[0]); 6869 reader.js_fill = NULL; 6870 reader.js_used = 0; 6871 if (json_decode_all(&reader, rettv, JSON_JS) != OK) 6872 EMSG(_(e_invarg)); 6873 } 6874 6875 /* 6876 * "js_encode()" function 6877 */ 6878 static void 6879 f_js_encode(typval_T *argvars, typval_T *rettv) 6880 { 6881 rettv->v_type = VAR_STRING; 6882 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS); 6883 } 6884 6885 /* 6886 * "json_decode()" function 6887 */ 6888 static void 6889 f_json_decode(typval_T *argvars, typval_T *rettv) 6890 { 6891 js_read_T reader; 6892 6893 reader.js_buf = get_tv_string(&argvars[0]); 6894 reader.js_fill = NULL; 6895 reader.js_used = 0; 6896 json_decode_all(&reader, rettv, 0); 6897 } 6898 6899 /* 6900 * "json_encode()" function 6901 */ 6902 static void 6903 f_json_encode(typval_T *argvars, typval_T *rettv) 6904 { 6905 rettv->v_type = VAR_STRING; 6906 rettv->vval.v_string = json_encode(&argvars[0], 0); 6907 } 6908 6909 /* 6910 * "keys()" function 6911 */ 6912 static void 6913 f_keys(typval_T *argvars, typval_T *rettv) 6914 { 6915 dict_list(argvars, rettv, 0); 6916 } 6917 6918 /* 6919 * "last_buffer_nr()" function. 6920 */ 6921 static void 6922 f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv) 6923 { 6924 int n = 0; 6925 buf_T *buf; 6926 6927 FOR_ALL_BUFFERS(buf) 6928 if (n < buf->b_fnum) 6929 n = buf->b_fnum; 6930 6931 rettv->vval.v_number = n; 6932 } 6933 6934 /* 6935 * "len()" function 6936 */ 6937 static void 6938 f_len(typval_T *argvars, typval_T *rettv) 6939 { 6940 switch (argvars[0].v_type) 6941 { 6942 case VAR_STRING: 6943 case VAR_NUMBER: 6944 rettv->vval.v_number = (varnumber_T)STRLEN( 6945 get_tv_string(&argvars[0])); 6946 break; 6947 case VAR_LIST: 6948 rettv->vval.v_number = list_len(argvars[0].vval.v_list); 6949 break; 6950 case VAR_DICT: 6951 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict); 6952 break; 6953 case VAR_UNKNOWN: 6954 case VAR_SPECIAL: 6955 case VAR_FLOAT: 6956 case VAR_FUNC: 6957 case VAR_PARTIAL: 6958 case VAR_JOB: 6959 case VAR_CHANNEL: 6960 EMSG(_("E701: Invalid type for len()")); 6961 break; 6962 } 6963 } 6964 6965 static void 6966 libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type) 6967 { 6968 #ifdef FEAT_LIBCALL 6969 char_u *string_in; 6970 char_u **string_result; 6971 int nr_result; 6972 #endif 6973 6974 rettv->v_type = type; 6975 if (type != VAR_NUMBER) 6976 rettv->vval.v_string = NULL; 6977 6978 if (check_restricted() || check_secure()) 6979 return; 6980 6981 #ifdef FEAT_LIBCALL 6982 /* The first two args must be strings, otherwise it's meaningless */ 6983 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING) 6984 { 6985 string_in = NULL; 6986 if (argvars[2].v_type == VAR_STRING) 6987 string_in = argvars[2].vval.v_string; 6988 if (type == VAR_NUMBER) 6989 string_result = NULL; 6990 else 6991 string_result = &rettv->vval.v_string; 6992 if (mch_libcall(argvars[0].vval.v_string, 6993 argvars[1].vval.v_string, 6994 string_in, 6995 argvars[2].vval.v_number, 6996 string_result, 6997 &nr_result) == OK 6998 && type == VAR_NUMBER) 6999 rettv->vval.v_number = nr_result; 7000 } 7001 #endif 7002 } 7003 7004 /* 7005 * "libcall()" function 7006 */ 7007 static void 7008 f_libcall(typval_T *argvars, typval_T *rettv) 7009 { 7010 libcall_common(argvars, rettv, VAR_STRING); 7011 } 7012 7013 /* 7014 * "libcallnr()" function 7015 */ 7016 static void 7017 f_libcallnr(typval_T *argvars, typval_T *rettv) 7018 { 7019 libcall_common(argvars, rettv, VAR_NUMBER); 7020 } 7021 7022 /* 7023 * "line(string)" function 7024 */ 7025 static void 7026 f_line(typval_T *argvars, typval_T *rettv) 7027 { 7028 linenr_T lnum = 0; 7029 pos_T *fp; 7030 int fnum; 7031 7032 fp = var2fpos(&argvars[0], TRUE, &fnum); 7033 if (fp != NULL) 7034 lnum = fp->lnum; 7035 rettv->vval.v_number = lnum; 7036 } 7037 7038 /* 7039 * "line2byte(lnum)" function 7040 */ 7041 static void 7042 f_line2byte(typval_T *argvars UNUSED, typval_T *rettv) 7043 { 7044 #ifndef FEAT_BYTEOFF 7045 rettv->vval.v_number = -1; 7046 #else 7047 linenr_T lnum; 7048 7049 lnum = get_tv_lnum(argvars); 7050 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) 7051 rettv->vval.v_number = -1; 7052 else 7053 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL); 7054 if (rettv->vval.v_number >= 0) 7055 ++rettv->vval.v_number; 7056 #endif 7057 } 7058 7059 /* 7060 * "lispindent(lnum)" function 7061 */ 7062 static void 7063 f_lispindent(typval_T *argvars UNUSED, typval_T *rettv) 7064 { 7065 #ifdef FEAT_LISP 7066 pos_T pos; 7067 linenr_T lnum; 7068 7069 pos = curwin->w_cursor; 7070 lnum = get_tv_lnum(argvars); 7071 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) 7072 { 7073 curwin->w_cursor.lnum = lnum; 7074 rettv->vval.v_number = get_lisp_indent(); 7075 curwin->w_cursor = pos; 7076 } 7077 else 7078 #endif 7079 rettv->vval.v_number = -1; 7080 } 7081 7082 /* 7083 * "localtime()" function 7084 */ 7085 static void 7086 f_localtime(typval_T *argvars UNUSED, typval_T *rettv) 7087 { 7088 rettv->vval.v_number = (varnumber_T)time(NULL); 7089 } 7090 7091 static void get_maparg(typval_T *argvars, typval_T *rettv, int exact); 7092 7093 static void 7094 get_maparg(typval_T *argvars, typval_T *rettv, int exact) 7095 { 7096 char_u *keys; 7097 char_u *which; 7098 char_u buf[NUMBUFLEN]; 7099 char_u *keys_buf = NULL; 7100 char_u *rhs; 7101 int mode; 7102 int abbr = FALSE; 7103 int get_dict = FALSE; 7104 mapblock_T *mp; 7105 int buffer_local; 7106 7107 /* return empty string for failure */ 7108 rettv->v_type = VAR_STRING; 7109 rettv->vval.v_string = NULL; 7110 7111 keys = get_tv_string(&argvars[0]); 7112 if (*keys == NUL) 7113 return; 7114 7115 if (argvars[1].v_type != VAR_UNKNOWN) 7116 { 7117 which = get_tv_string_buf_chk(&argvars[1], buf); 7118 if (argvars[2].v_type != VAR_UNKNOWN) 7119 { 7120 abbr = (int)get_tv_number(&argvars[2]); 7121 if (argvars[3].v_type != VAR_UNKNOWN) 7122 get_dict = (int)get_tv_number(&argvars[3]); 7123 } 7124 } 7125 else 7126 which = (char_u *)""; 7127 if (which == NULL) 7128 return; 7129 7130 mode = get_map_mode(&which, 0); 7131 7132 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE); 7133 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local); 7134 vim_free(keys_buf); 7135 7136 if (!get_dict) 7137 { 7138 /* Return a string. */ 7139 if (rhs != NULL) 7140 rettv->vval.v_string = str2special_save(rhs, FALSE); 7141 7142 } 7143 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL) 7144 { 7145 /* Return a dictionary. */ 7146 char_u *lhs = str2special_save(mp->m_keys, TRUE); 7147 char_u *mapmode = map_mode_to_chars(mp->m_mode); 7148 dict_T *dict = rettv->vval.v_dict; 7149 7150 dict_add_nr_str(dict, "lhs", 0L, lhs); 7151 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str); 7152 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL); 7153 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL); 7154 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL); 7155 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL); 7156 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL); 7157 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL); 7158 dict_add_nr_str(dict, "mode", 0L, mapmode); 7159 7160 vim_free(lhs); 7161 vim_free(mapmode); 7162 } 7163 } 7164 7165 #ifdef FEAT_FLOAT 7166 /* 7167 * "log()" function 7168 */ 7169 static void 7170 f_log(typval_T *argvars, typval_T *rettv) 7171 { 7172 float_T f = 0.0; 7173 7174 rettv->v_type = VAR_FLOAT; 7175 if (get_float_arg(argvars, &f) == OK) 7176 rettv->vval.v_float = log(f); 7177 else 7178 rettv->vval.v_float = 0.0; 7179 } 7180 7181 /* 7182 * "log10()" function 7183 */ 7184 static void 7185 f_log10(typval_T *argvars, typval_T *rettv) 7186 { 7187 float_T f = 0.0; 7188 7189 rettv->v_type = VAR_FLOAT; 7190 if (get_float_arg(argvars, &f) == OK) 7191 rettv->vval.v_float = log10(f); 7192 else 7193 rettv->vval.v_float = 0.0; 7194 } 7195 #endif 7196 7197 #ifdef FEAT_LUA 7198 /* 7199 * "luaeval()" function 7200 */ 7201 static void 7202 f_luaeval(typval_T *argvars, typval_T *rettv) 7203 { 7204 char_u *str; 7205 char_u buf[NUMBUFLEN]; 7206 7207 str = get_tv_string_buf(&argvars[0], buf); 7208 do_luaeval(str, argvars + 1, rettv); 7209 } 7210 #endif 7211 7212 /* 7213 * "map()" function 7214 */ 7215 static void 7216 f_map(typval_T *argvars, typval_T *rettv) 7217 { 7218 filter_map(argvars, rettv, TRUE); 7219 } 7220 7221 /* 7222 * "maparg()" function 7223 */ 7224 static void 7225 f_maparg(typval_T *argvars, typval_T *rettv) 7226 { 7227 get_maparg(argvars, rettv, TRUE); 7228 } 7229 7230 /* 7231 * "mapcheck()" function 7232 */ 7233 static void 7234 f_mapcheck(typval_T *argvars, typval_T *rettv) 7235 { 7236 get_maparg(argvars, rettv, FALSE); 7237 } 7238 7239 static void find_some_match(typval_T *argvars, typval_T *rettv, int start); 7240 7241 static void 7242 find_some_match(typval_T *argvars, typval_T *rettv, int type) 7243 { 7244 char_u *str = NULL; 7245 long len = 0; 7246 char_u *expr = NULL; 7247 char_u *pat; 7248 regmatch_T regmatch; 7249 char_u patbuf[NUMBUFLEN]; 7250 char_u strbuf[NUMBUFLEN]; 7251 char_u *save_cpo; 7252 long start = 0; 7253 long nth = 1; 7254 colnr_T startcol = 0; 7255 int match = 0; 7256 list_T *l = NULL; 7257 listitem_T *li = NULL; 7258 long idx = 0; 7259 char_u *tofree = NULL; 7260 7261 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ 7262 save_cpo = p_cpo; 7263 p_cpo = (char_u *)""; 7264 7265 rettv->vval.v_number = -1; 7266 if (type == 3 || type == 4) 7267 { 7268 /* type 3: return empty list when there are no matches. 7269 * type 4: return ["", -1, -1, -1] */ 7270 if (rettv_list_alloc(rettv) == FAIL) 7271 goto theend; 7272 if (type == 4 7273 && (list_append_string(rettv->vval.v_list, 7274 (char_u *)"", 0) == FAIL 7275 || list_append_number(rettv->vval.v_list, 7276 (varnumber_T)-1) == FAIL 7277 || list_append_number(rettv->vval.v_list, 7278 (varnumber_T)-1) == FAIL 7279 || list_append_number(rettv->vval.v_list, 7280 (varnumber_T)-1) == FAIL)) 7281 { 7282 list_free(rettv->vval.v_list); 7283 rettv->vval.v_list = NULL; 7284 goto theend; 7285 } 7286 } 7287 else if (type == 2) 7288 { 7289 rettv->v_type = VAR_STRING; 7290 rettv->vval.v_string = NULL; 7291 } 7292 7293 if (argvars[0].v_type == VAR_LIST) 7294 { 7295 if ((l = argvars[0].vval.v_list) == NULL) 7296 goto theend; 7297 li = l->lv_first; 7298 } 7299 else 7300 { 7301 expr = str = get_tv_string(&argvars[0]); 7302 len = (long)STRLEN(str); 7303 } 7304 7305 pat = get_tv_string_buf_chk(&argvars[1], patbuf); 7306 if (pat == NULL) 7307 goto theend; 7308 7309 if (argvars[2].v_type != VAR_UNKNOWN) 7310 { 7311 int error = FALSE; 7312 7313 start = (long)get_tv_number_chk(&argvars[2], &error); 7314 if (error) 7315 goto theend; 7316 if (l != NULL) 7317 { 7318 li = list_find(l, start); 7319 if (li == NULL) 7320 goto theend; 7321 idx = l->lv_idx; /* use the cached index */ 7322 } 7323 else 7324 { 7325 if (start < 0) 7326 start = 0; 7327 if (start > len) 7328 goto theend; 7329 /* When "count" argument is there ignore matches before "start", 7330 * otherwise skip part of the string. Differs when pattern is "^" 7331 * or "\<". */ 7332 if (argvars[3].v_type != VAR_UNKNOWN) 7333 startcol = start; 7334 else 7335 { 7336 str += start; 7337 len -= start; 7338 } 7339 } 7340 7341 if (argvars[3].v_type != VAR_UNKNOWN) 7342 nth = (long)get_tv_number_chk(&argvars[3], &error); 7343 if (error) 7344 goto theend; 7345 } 7346 7347 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); 7348 if (regmatch.regprog != NULL) 7349 { 7350 regmatch.rm_ic = p_ic; 7351 7352 for (;;) 7353 { 7354 if (l != NULL) 7355 { 7356 if (li == NULL) 7357 { 7358 match = FALSE; 7359 break; 7360 } 7361 vim_free(tofree); 7362 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0); 7363 if (str == NULL) 7364 break; 7365 } 7366 7367 match = vim_regexec_nl(®match, str, (colnr_T)startcol); 7368 7369 if (match && --nth <= 0) 7370 break; 7371 if (l == NULL && !match) 7372 break; 7373 7374 /* Advance to just after the match. */ 7375 if (l != NULL) 7376 { 7377 li = li->li_next; 7378 ++idx; 7379 } 7380 else 7381 { 7382 #ifdef FEAT_MBYTE 7383 startcol = (colnr_T)(regmatch.startp[0] 7384 + (*mb_ptr2len)(regmatch.startp[0]) - str); 7385 #else 7386 startcol = (colnr_T)(regmatch.startp[0] + 1 - str); 7387 #endif 7388 if (startcol > (colnr_T)len 7389 || str + startcol <= regmatch.startp[0]) 7390 { 7391 match = FALSE; 7392 break; 7393 } 7394 } 7395 } 7396 7397 if (match) 7398 { 7399 if (type == 4) 7400 { 7401 listitem_T *li1 = rettv->vval.v_list->lv_first; 7402 listitem_T *li2 = li1->li_next; 7403 listitem_T *li3 = li2->li_next; 7404 listitem_T *li4 = li3->li_next; 7405 7406 vim_free(li1->li_tv.vval.v_string); 7407 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0], 7408 (int)(regmatch.endp[0] - regmatch.startp[0])); 7409 li3->li_tv.vval.v_number = 7410 (varnumber_T)(regmatch.startp[0] - expr); 7411 li4->li_tv.vval.v_number = 7412 (varnumber_T)(regmatch.endp[0] - expr); 7413 if (l != NULL) 7414 li2->li_tv.vval.v_number = (varnumber_T)idx; 7415 } 7416 else if (type == 3) 7417 { 7418 int i; 7419 7420 /* return list with matched string and submatches */ 7421 for (i = 0; i < NSUBEXP; ++i) 7422 { 7423 if (regmatch.endp[i] == NULL) 7424 { 7425 if (list_append_string(rettv->vval.v_list, 7426 (char_u *)"", 0) == FAIL) 7427 break; 7428 } 7429 else if (list_append_string(rettv->vval.v_list, 7430 regmatch.startp[i], 7431 (int)(regmatch.endp[i] - regmatch.startp[i])) 7432 == FAIL) 7433 break; 7434 } 7435 } 7436 else if (type == 2) 7437 { 7438 /* return matched string */ 7439 if (l != NULL) 7440 copy_tv(&li->li_tv, rettv); 7441 else 7442 rettv->vval.v_string = vim_strnsave(regmatch.startp[0], 7443 (int)(regmatch.endp[0] - regmatch.startp[0])); 7444 } 7445 else if (l != NULL) 7446 rettv->vval.v_number = idx; 7447 else 7448 { 7449 if (type != 0) 7450 rettv->vval.v_number = 7451 (varnumber_T)(regmatch.startp[0] - str); 7452 else 7453 rettv->vval.v_number = 7454 (varnumber_T)(regmatch.endp[0] - str); 7455 rettv->vval.v_number += (varnumber_T)(str - expr); 7456 } 7457 } 7458 vim_regfree(regmatch.regprog); 7459 } 7460 7461 if (type == 4 && l == NULL) 7462 /* matchstrpos() without a list: drop the second item. */ 7463 listitem_remove(rettv->vval.v_list, 7464 rettv->vval.v_list->lv_first->li_next); 7465 7466 theend: 7467 vim_free(tofree); 7468 p_cpo = save_cpo; 7469 } 7470 7471 /* 7472 * "match()" function 7473 */ 7474 static void 7475 f_match(typval_T *argvars, typval_T *rettv) 7476 { 7477 find_some_match(argvars, rettv, 1); 7478 } 7479 7480 /* 7481 * "matchadd()" function 7482 */ 7483 static void 7484 f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 7485 { 7486 #ifdef FEAT_SEARCH_EXTRA 7487 char_u buf[NUMBUFLEN]; 7488 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */ 7489 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */ 7490 int prio = 10; /* default priority */ 7491 int id = -1; 7492 int error = FALSE; 7493 char_u *conceal_char = NULL; 7494 7495 rettv->vval.v_number = -1; 7496 7497 if (grp == NULL || pat == NULL) 7498 return; 7499 if (argvars[2].v_type != VAR_UNKNOWN) 7500 { 7501 prio = (int)get_tv_number_chk(&argvars[2], &error); 7502 if (argvars[3].v_type != VAR_UNKNOWN) 7503 { 7504 id = (int)get_tv_number_chk(&argvars[3], &error); 7505 if (argvars[4].v_type != VAR_UNKNOWN) 7506 { 7507 if (argvars[4].v_type != VAR_DICT) 7508 { 7509 EMSG(_(e_dictreq)); 7510 return; 7511 } 7512 if (dict_find(argvars[4].vval.v_dict, 7513 (char_u *)"conceal", -1) != NULL) 7514 conceal_char = get_dict_string(argvars[4].vval.v_dict, 7515 (char_u *)"conceal", FALSE); 7516 } 7517 } 7518 } 7519 if (error == TRUE) 7520 return; 7521 if (id >= 1 && id <= 3) 7522 { 7523 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id); 7524 return; 7525 } 7526 7527 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL, 7528 conceal_char); 7529 #endif 7530 } 7531 7532 /* 7533 * "matchaddpos()" function 7534 */ 7535 static void 7536 f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 7537 { 7538 #ifdef FEAT_SEARCH_EXTRA 7539 char_u buf[NUMBUFLEN]; 7540 char_u *group; 7541 int prio = 10; 7542 int id = -1; 7543 int error = FALSE; 7544 list_T *l; 7545 char_u *conceal_char = NULL; 7546 7547 rettv->vval.v_number = -1; 7548 7549 group = get_tv_string_buf_chk(&argvars[0], buf); 7550 if (group == NULL) 7551 return; 7552 7553 if (argvars[1].v_type != VAR_LIST) 7554 { 7555 EMSG2(_(e_listarg), "matchaddpos()"); 7556 return; 7557 } 7558 l = argvars[1].vval.v_list; 7559 if (l == NULL) 7560 return; 7561 7562 if (argvars[2].v_type != VAR_UNKNOWN) 7563 { 7564 prio = (int)get_tv_number_chk(&argvars[2], &error); 7565 if (argvars[3].v_type != VAR_UNKNOWN) 7566 { 7567 id = (int)get_tv_number_chk(&argvars[3], &error); 7568 if (argvars[4].v_type != VAR_UNKNOWN) 7569 { 7570 if (argvars[4].v_type != VAR_DICT) 7571 { 7572 EMSG(_(e_dictreq)); 7573 return; 7574 } 7575 if (dict_find(argvars[4].vval.v_dict, 7576 (char_u *)"conceal", -1) != NULL) 7577 conceal_char = get_dict_string(argvars[4].vval.v_dict, 7578 (char_u *)"conceal", FALSE); 7579 } 7580 } 7581 } 7582 if (error == TRUE) 7583 return; 7584 7585 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */ 7586 if (id == 1 || id == 2) 7587 { 7588 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id); 7589 return; 7590 } 7591 7592 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l, 7593 conceal_char); 7594 #endif 7595 } 7596 7597 /* 7598 * "matcharg()" function 7599 */ 7600 static void 7601 f_matcharg(typval_T *argvars UNUSED, typval_T *rettv) 7602 { 7603 if (rettv_list_alloc(rettv) == OK) 7604 { 7605 #ifdef FEAT_SEARCH_EXTRA 7606 int id = (int)get_tv_number(&argvars[0]); 7607 matchitem_T *m; 7608 7609 if (id >= 1 && id <= 3) 7610 { 7611 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL) 7612 { 7613 list_append_string(rettv->vval.v_list, 7614 syn_id2name(m->hlg_id), -1); 7615 list_append_string(rettv->vval.v_list, m->pattern, -1); 7616 } 7617 else 7618 { 7619 list_append_string(rettv->vval.v_list, NULL, -1); 7620 list_append_string(rettv->vval.v_list, NULL, -1); 7621 } 7622 } 7623 #endif 7624 } 7625 } 7626 7627 /* 7628 * "matchdelete()" function 7629 */ 7630 static void 7631 f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 7632 { 7633 #ifdef FEAT_SEARCH_EXTRA 7634 rettv->vval.v_number = match_delete(curwin, 7635 (int)get_tv_number(&argvars[0]), TRUE); 7636 #endif 7637 } 7638 7639 /* 7640 * "matchend()" function 7641 */ 7642 static void 7643 f_matchend(typval_T *argvars, typval_T *rettv) 7644 { 7645 find_some_match(argvars, rettv, 0); 7646 } 7647 7648 /* 7649 * "matchlist()" function 7650 */ 7651 static void 7652 f_matchlist(typval_T *argvars, typval_T *rettv) 7653 { 7654 find_some_match(argvars, rettv, 3); 7655 } 7656 7657 /* 7658 * "matchstr()" function 7659 */ 7660 static void 7661 f_matchstr(typval_T *argvars, typval_T *rettv) 7662 { 7663 find_some_match(argvars, rettv, 2); 7664 } 7665 7666 /* 7667 * "matchstrpos()" function 7668 */ 7669 static void 7670 f_matchstrpos(typval_T *argvars, typval_T *rettv) 7671 { 7672 find_some_match(argvars, rettv, 4); 7673 } 7674 7675 static void max_min(typval_T *argvars, typval_T *rettv, int domax); 7676 7677 static void 7678 max_min(typval_T *argvars, typval_T *rettv, int domax) 7679 { 7680 varnumber_T n = 0; 7681 varnumber_T i; 7682 int error = FALSE; 7683 7684 if (argvars[0].v_type == VAR_LIST) 7685 { 7686 list_T *l; 7687 listitem_T *li; 7688 7689 l = argvars[0].vval.v_list; 7690 if (l != NULL) 7691 { 7692 li = l->lv_first; 7693 if (li != NULL) 7694 { 7695 n = get_tv_number_chk(&li->li_tv, &error); 7696 for (;;) 7697 { 7698 li = li->li_next; 7699 if (li == NULL) 7700 break; 7701 i = get_tv_number_chk(&li->li_tv, &error); 7702 if (domax ? i > n : i < n) 7703 n = i; 7704 } 7705 } 7706 } 7707 } 7708 else if (argvars[0].v_type == VAR_DICT) 7709 { 7710 dict_T *d; 7711 int first = TRUE; 7712 hashitem_T *hi; 7713 int todo; 7714 7715 d = argvars[0].vval.v_dict; 7716 if (d != NULL) 7717 { 7718 todo = (int)d->dv_hashtab.ht_used; 7719 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) 7720 { 7721 if (!HASHITEM_EMPTY(hi)) 7722 { 7723 --todo; 7724 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error); 7725 if (first) 7726 { 7727 n = i; 7728 first = FALSE; 7729 } 7730 else if (domax ? i > n : i < n) 7731 n = i; 7732 } 7733 } 7734 } 7735 } 7736 else 7737 EMSG2(_(e_listdictarg), domax ? "max()" : "min()"); 7738 rettv->vval.v_number = error ? 0 : n; 7739 } 7740 7741 /* 7742 * "max()" function 7743 */ 7744 static void 7745 f_max(typval_T *argvars, typval_T *rettv) 7746 { 7747 max_min(argvars, rettv, TRUE); 7748 } 7749 7750 /* 7751 * "min()" function 7752 */ 7753 static void 7754 f_min(typval_T *argvars, typval_T *rettv) 7755 { 7756 max_min(argvars, rettv, FALSE); 7757 } 7758 7759 static int mkdir_recurse(char_u *dir, int prot); 7760 7761 /* 7762 * Create the directory in which "dir" is located, and higher levels when 7763 * needed. 7764 * Return OK or FAIL. 7765 */ 7766 static int 7767 mkdir_recurse(char_u *dir, int prot) 7768 { 7769 char_u *p; 7770 char_u *updir; 7771 int r = FAIL; 7772 7773 /* Get end of directory name in "dir". 7774 * We're done when it's "/" or "c:/". */ 7775 p = gettail_sep(dir); 7776 if (p <= get_past_head(dir)) 7777 return OK; 7778 7779 /* If the directory exists we're done. Otherwise: create it.*/ 7780 updir = vim_strnsave(dir, (int)(p - dir)); 7781 if (updir == NULL) 7782 return FAIL; 7783 if (mch_isdir(updir)) 7784 r = OK; 7785 else if (mkdir_recurse(updir, prot) == OK) 7786 r = vim_mkdir_emsg(updir, prot); 7787 vim_free(updir); 7788 return r; 7789 } 7790 7791 #ifdef vim_mkdir 7792 /* 7793 * "mkdir()" function 7794 */ 7795 static void 7796 f_mkdir(typval_T *argvars, typval_T *rettv) 7797 { 7798 char_u *dir; 7799 char_u buf[NUMBUFLEN]; 7800 int prot = 0755; 7801 7802 rettv->vval.v_number = FAIL; 7803 if (check_restricted() || check_secure()) 7804 return; 7805 7806 dir = get_tv_string_buf(&argvars[0], buf); 7807 if (*dir == NUL) 7808 rettv->vval.v_number = FAIL; 7809 else 7810 { 7811 if (*gettail(dir) == NUL) 7812 /* remove trailing slashes */ 7813 *gettail_sep(dir) = NUL; 7814 7815 if (argvars[1].v_type != VAR_UNKNOWN) 7816 { 7817 if (argvars[2].v_type != VAR_UNKNOWN) 7818 prot = (int)get_tv_number_chk(&argvars[2], NULL); 7819 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0) 7820 mkdir_recurse(dir, prot); 7821 } 7822 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot); 7823 } 7824 } 7825 #endif 7826 7827 /* 7828 * "mode()" function 7829 */ 7830 static void 7831 f_mode(typval_T *argvars, typval_T *rettv) 7832 { 7833 char_u buf[3]; 7834 7835 buf[1] = NUL; 7836 buf[2] = NUL; 7837 7838 if (time_for_testing == 93784) 7839 { 7840 /* Testing the two-character code. */ 7841 buf[0] = 'x'; 7842 buf[1] = '!'; 7843 } 7844 else if (VIsual_active) 7845 { 7846 if (VIsual_select) 7847 buf[0] = VIsual_mode + 's' - 'v'; 7848 else 7849 buf[0] = VIsual_mode; 7850 } 7851 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE 7852 || State == CONFIRM) 7853 { 7854 buf[0] = 'r'; 7855 if (State == ASKMORE) 7856 buf[1] = 'm'; 7857 else if (State == CONFIRM) 7858 buf[1] = '?'; 7859 } 7860 else if (State == EXTERNCMD) 7861 buf[0] = '!'; 7862 else if (State & INSERT) 7863 { 7864 #ifdef FEAT_VREPLACE 7865 if (State & VREPLACE_FLAG) 7866 { 7867 buf[0] = 'R'; 7868 buf[1] = 'v'; 7869 } 7870 else 7871 #endif 7872 { 7873 if (State & REPLACE_FLAG) 7874 buf[0] = 'R'; 7875 else 7876 buf[0] = 'i'; 7877 #ifdef FEAT_INS_EXPAND 7878 if (ins_compl_active()) 7879 buf[1] = 'c'; 7880 else if (ctrl_x_mode == 1) 7881 buf[1] = 'x'; 7882 #endif 7883 } 7884 } 7885 else if ((State & CMDLINE) || exmode_active) 7886 { 7887 buf[0] = 'c'; 7888 if (exmode_active == EXMODE_VIM) 7889 buf[1] = 'v'; 7890 else if (exmode_active == EXMODE_NORMAL) 7891 buf[1] = 'e'; 7892 } 7893 else 7894 { 7895 buf[0] = 'n'; 7896 if (finish_op) 7897 buf[1] = 'o'; 7898 } 7899 7900 /* Clear out the minor mode when the argument is not a non-zero number or 7901 * non-empty string. */ 7902 if (!non_zero_arg(&argvars[0])) 7903 buf[1] = NUL; 7904 7905 rettv->vval.v_string = vim_strsave(buf); 7906 rettv->v_type = VAR_STRING; 7907 } 7908 7909 #if defined(FEAT_MZSCHEME) || defined(PROTO) 7910 /* 7911 * "mzeval()" function 7912 */ 7913 static void 7914 f_mzeval(typval_T *argvars, typval_T *rettv) 7915 { 7916 char_u *str; 7917 char_u buf[NUMBUFLEN]; 7918 7919 str = get_tv_string_buf(&argvars[0], buf); 7920 do_mzeval(str, rettv); 7921 } 7922 7923 void 7924 mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv) 7925 { 7926 typval_T argvars[3]; 7927 7928 argvars[0].v_type = VAR_STRING; 7929 argvars[0].vval.v_string = name; 7930 copy_tv(args, &argvars[1]); 7931 argvars[2].v_type = VAR_UNKNOWN; 7932 f_call(argvars, rettv); 7933 clear_tv(&argvars[1]); 7934 } 7935 #endif 7936 7937 /* 7938 * "nextnonblank()" function 7939 */ 7940 static void 7941 f_nextnonblank(typval_T *argvars, typval_T *rettv) 7942 { 7943 linenr_T lnum; 7944 7945 for (lnum = get_tv_lnum(argvars); ; ++lnum) 7946 { 7947 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count) 7948 { 7949 lnum = 0; 7950 break; 7951 } 7952 if (*skipwhite(ml_get(lnum)) != NUL) 7953 break; 7954 } 7955 rettv->vval.v_number = lnum; 7956 } 7957 7958 /* 7959 * "nr2char()" function 7960 */ 7961 static void 7962 f_nr2char(typval_T *argvars, typval_T *rettv) 7963 { 7964 char_u buf[NUMBUFLEN]; 7965 7966 #ifdef FEAT_MBYTE 7967 if (has_mbyte) 7968 { 7969 int utf8 = 0; 7970 7971 if (argvars[1].v_type != VAR_UNKNOWN) 7972 utf8 = (int)get_tv_number_chk(&argvars[1], NULL); 7973 if (utf8) 7974 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL; 7975 else 7976 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL; 7977 } 7978 else 7979 #endif 7980 { 7981 buf[0] = (char_u)get_tv_number(&argvars[0]); 7982 buf[1] = NUL; 7983 } 7984 rettv->v_type = VAR_STRING; 7985 rettv->vval.v_string = vim_strsave(buf); 7986 } 7987 7988 /* 7989 * "or(expr, expr)" function 7990 */ 7991 static void 7992 f_or(typval_T *argvars, typval_T *rettv) 7993 { 7994 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) 7995 | get_tv_number_chk(&argvars[1], NULL); 7996 } 7997 7998 /* 7999 * "pathshorten()" function 8000 */ 8001 static void 8002 f_pathshorten(typval_T *argvars, typval_T *rettv) 8003 { 8004 char_u *p; 8005 8006 rettv->v_type = VAR_STRING; 8007 p = get_tv_string_chk(&argvars[0]); 8008 if (p == NULL) 8009 rettv->vval.v_string = NULL; 8010 else 8011 { 8012 p = vim_strsave(p); 8013 rettv->vval.v_string = p; 8014 if (p != NULL) 8015 shorten_dir(p); 8016 } 8017 } 8018 8019 #ifdef FEAT_PERL 8020 /* 8021 * "perleval()" function 8022 */ 8023 static void 8024 f_perleval(typval_T *argvars, typval_T *rettv) 8025 { 8026 char_u *str; 8027 char_u buf[NUMBUFLEN]; 8028 8029 str = get_tv_string_buf(&argvars[0], buf); 8030 do_perleval(str, rettv); 8031 } 8032 #endif 8033 8034 #ifdef FEAT_FLOAT 8035 /* 8036 * "pow()" function 8037 */ 8038 static void 8039 f_pow(typval_T *argvars, typval_T *rettv) 8040 { 8041 float_T fx = 0.0, fy = 0.0; 8042 8043 rettv->v_type = VAR_FLOAT; 8044 if (get_float_arg(argvars, &fx) == OK 8045 && get_float_arg(&argvars[1], &fy) == OK) 8046 rettv->vval.v_float = pow(fx, fy); 8047 else 8048 rettv->vval.v_float = 0.0; 8049 } 8050 #endif 8051 8052 /* 8053 * "prevnonblank()" function 8054 */ 8055 static void 8056 f_prevnonblank(typval_T *argvars, typval_T *rettv) 8057 { 8058 linenr_T lnum; 8059 8060 lnum = get_tv_lnum(argvars); 8061 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) 8062 lnum = 0; 8063 else 8064 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL) 8065 --lnum; 8066 rettv->vval.v_number = lnum; 8067 } 8068 8069 /* This dummy va_list is here because: 8070 * - passing a NULL pointer doesn't work when va_list isn't a pointer 8071 * - locally in the function results in a "used before set" warning 8072 * - using va_start() to initialize it gives "function with fixed args" error */ 8073 static va_list ap; 8074 8075 /* 8076 * "printf()" function 8077 */ 8078 static void 8079 f_printf(typval_T *argvars, typval_T *rettv) 8080 { 8081 char_u buf[NUMBUFLEN]; 8082 int len; 8083 char_u *s; 8084 int saved_did_emsg = did_emsg; 8085 char *fmt; 8086 8087 rettv->v_type = VAR_STRING; 8088 rettv->vval.v_string = NULL; 8089 8090 /* Get the required length, allocate the buffer and do it for real. */ 8091 did_emsg = FALSE; 8092 fmt = (char *)get_tv_string_buf(&argvars[0], buf); 8093 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1); 8094 if (!did_emsg) 8095 { 8096 s = alloc(len + 1); 8097 if (s != NULL) 8098 { 8099 rettv->vval.v_string = s; 8100 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt, 8101 ap, argvars + 1); 8102 } 8103 } 8104 did_emsg |= saved_did_emsg; 8105 } 8106 8107 /* 8108 * "pumvisible()" function 8109 */ 8110 static void 8111 f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 8112 { 8113 #ifdef FEAT_INS_EXPAND 8114 if (pum_visible()) 8115 rettv->vval.v_number = 1; 8116 #endif 8117 } 8118 8119 #ifdef FEAT_PYTHON3 8120 /* 8121 * "py3eval()" function 8122 */ 8123 static void 8124 f_py3eval(typval_T *argvars, typval_T *rettv) 8125 { 8126 char_u *str; 8127 char_u buf[NUMBUFLEN]; 8128 8129 if (p_pyx == 0) 8130 p_pyx = 3; 8131 8132 str = get_tv_string_buf(&argvars[0], buf); 8133 do_py3eval(str, rettv); 8134 } 8135 #endif 8136 8137 #ifdef FEAT_PYTHON 8138 /* 8139 * "pyeval()" function 8140 */ 8141 static void 8142 f_pyeval(typval_T *argvars, typval_T *rettv) 8143 { 8144 char_u *str; 8145 char_u buf[NUMBUFLEN]; 8146 8147 if (p_pyx == 0) 8148 p_pyx = 2; 8149 8150 str = get_tv_string_buf(&argvars[0], buf); 8151 do_pyeval(str, rettv); 8152 } 8153 #endif 8154 8155 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) 8156 /* 8157 * "pyxeval()" function 8158 */ 8159 static void 8160 f_pyxeval(typval_T *argvars, typval_T *rettv) 8161 { 8162 # if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3) 8163 init_pyxversion(); 8164 if (p_pyx == 2) 8165 f_pyeval(argvars, rettv); 8166 else 8167 f_py3eval(argvars, rettv); 8168 # elif defined(FEAT_PYTHON) 8169 f_pyeval(argvars, rettv); 8170 # elif defined(FEAT_PYTHON3) 8171 f_py3eval(argvars, rettv); 8172 # endif 8173 } 8174 #endif 8175 8176 /* 8177 * "range()" function 8178 */ 8179 static void 8180 f_range(typval_T *argvars, typval_T *rettv) 8181 { 8182 varnumber_T start; 8183 varnumber_T end; 8184 varnumber_T stride = 1; 8185 varnumber_T i; 8186 int error = FALSE; 8187 8188 start = get_tv_number_chk(&argvars[0], &error); 8189 if (argvars[1].v_type == VAR_UNKNOWN) 8190 { 8191 end = start - 1; 8192 start = 0; 8193 } 8194 else 8195 { 8196 end = get_tv_number_chk(&argvars[1], &error); 8197 if (argvars[2].v_type != VAR_UNKNOWN) 8198 stride = get_tv_number_chk(&argvars[2], &error); 8199 } 8200 8201 if (error) 8202 return; /* type error; errmsg already given */ 8203 if (stride == 0) 8204 EMSG(_("E726: Stride is zero")); 8205 else if (stride > 0 ? end + 1 < start : end - 1 > start) 8206 EMSG(_("E727: Start past end")); 8207 else 8208 { 8209 if (rettv_list_alloc(rettv) == OK) 8210 for (i = start; stride > 0 ? i <= end : i >= end; i += stride) 8211 if (list_append_number(rettv->vval.v_list, 8212 (varnumber_T)i) == FAIL) 8213 break; 8214 } 8215 } 8216 8217 /* 8218 * "readfile()" function 8219 */ 8220 static void 8221 f_readfile(typval_T *argvars, typval_T *rettv) 8222 { 8223 int binary = FALSE; 8224 int failed = FALSE; 8225 char_u *fname; 8226 FILE *fd; 8227 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */ 8228 int io_size = sizeof(buf); 8229 int readlen; /* size of last fread() */ 8230 char_u *prev = NULL; /* previously read bytes, if any */ 8231 long prevlen = 0; /* length of data in prev */ 8232 long prevsize = 0; /* size of prev buffer */ 8233 long maxline = MAXLNUM; 8234 long cnt = 0; 8235 char_u *p; /* position in buf */ 8236 char_u *start; /* start of current line */ 8237 8238 if (argvars[1].v_type != VAR_UNKNOWN) 8239 { 8240 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0) 8241 binary = TRUE; 8242 if (argvars[2].v_type != VAR_UNKNOWN) 8243 maxline = (long)get_tv_number(&argvars[2]); 8244 } 8245 8246 if (rettv_list_alloc(rettv) == FAIL) 8247 return; 8248 8249 /* Always open the file in binary mode, library functions have a mind of 8250 * their own about CR-LF conversion. */ 8251 fname = get_tv_string(&argvars[0]); 8252 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL) 8253 { 8254 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname); 8255 return; 8256 } 8257 8258 while (cnt < maxline || maxline < 0) 8259 { 8260 readlen = (int)fread(buf, 1, io_size, fd); 8261 8262 /* This for loop processes what was read, but is also entered at end 8263 * of file so that either: 8264 * - an incomplete line gets written 8265 * - a "binary" file gets an empty line at the end if it ends in a 8266 * newline. */ 8267 for (p = buf, start = buf; 8268 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary)); 8269 ++p) 8270 { 8271 if (*p == '\n' || readlen <= 0) 8272 { 8273 listitem_T *li; 8274 char_u *s = NULL; 8275 long_u len = p - start; 8276 8277 /* Finished a line. Remove CRs before NL. */ 8278 if (readlen > 0 && !binary) 8279 { 8280 while (len > 0 && start[len - 1] == '\r') 8281 --len; 8282 /* removal may cross back to the "prev" string */ 8283 if (len == 0) 8284 while (prevlen > 0 && prev[prevlen - 1] == '\r') 8285 --prevlen; 8286 } 8287 if (prevlen == 0) 8288 s = vim_strnsave(start, (int)len); 8289 else 8290 { 8291 /* Change "prev" buffer to be the right size. This way 8292 * the bytes are only copied once, and very long lines are 8293 * allocated only once. */ 8294 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL) 8295 { 8296 mch_memmove(s + prevlen, start, len); 8297 s[prevlen + len] = NUL; 8298 prev = NULL; /* the list will own the string */ 8299 prevlen = prevsize = 0; 8300 } 8301 } 8302 if (s == NULL) 8303 { 8304 do_outofmem_msg((long_u) prevlen + len + 1); 8305 failed = TRUE; 8306 break; 8307 } 8308 8309 if ((li = listitem_alloc()) == NULL) 8310 { 8311 vim_free(s); 8312 failed = TRUE; 8313 break; 8314 } 8315 li->li_tv.v_type = VAR_STRING; 8316 li->li_tv.v_lock = 0; 8317 li->li_tv.vval.v_string = s; 8318 list_append(rettv->vval.v_list, li); 8319 8320 start = p + 1; /* step over newline */ 8321 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0) 8322 break; 8323 } 8324 else if (*p == NUL) 8325 *p = '\n'; 8326 #ifdef FEAT_MBYTE 8327 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this 8328 * when finding the BF and check the previous two bytes. */ 8329 else if (*p == 0xbf && enc_utf8 && !binary) 8330 { 8331 /* Find the two bytes before the 0xbf. If p is at buf, or buf 8332 * + 1, these may be in the "prev" string. */ 8333 char_u back1 = p >= buf + 1 ? p[-1] 8334 : prevlen >= 1 ? prev[prevlen - 1] : NUL; 8335 char_u back2 = p >= buf + 2 ? p[-2] 8336 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1] 8337 : prevlen >= 2 ? prev[prevlen - 2] : NUL; 8338 8339 if (back2 == 0xef && back1 == 0xbb) 8340 { 8341 char_u *dest = p - 2; 8342 8343 /* Usually a BOM is at the beginning of a file, and so at 8344 * the beginning of a line; then we can just step over it. 8345 */ 8346 if (start == dest) 8347 start = p + 1; 8348 else 8349 { 8350 /* have to shuffle buf to close gap */ 8351 int adjust_prevlen = 0; 8352 8353 if (dest < buf) 8354 { 8355 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */ 8356 dest = buf; 8357 } 8358 if (readlen > p - buf + 1) 8359 mch_memmove(dest, p + 1, readlen - (p - buf) - 1); 8360 readlen -= 3 - adjust_prevlen; 8361 prevlen -= adjust_prevlen; 8362 p = dest - 1; 8363 } 8364 } 8365 } 8366 #endif 8367 } /* for */ 8368 8369 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0) 8370 break; 8371 if (start < p) 8372 { 8373 /* There's part of a line in buf, store it in "prev". */ 8374 if (p - start + prevlen >= prevsize) 8375 { 8376 /* need bigger "prev" buffer */ 8377 char_u *newprev; 8378 8379 /* A common use case is ordinary text files and "prev" gets a 8380 * fragment of a line, so the first allocation is made 8381 * small, to avoid repeatedly 'allocing' large and 8382 * 'reallocing' small. */ 8383 if (prevsize == 0) 8384 prevsize = (long)(p - start); 8385 else 8386 { 8387 long grow50pc = (prevsize * 3) / 2; 8388 long growmin = (long)((p - start) * 2 + prevlen); 8389 prevsize = grow50pc > growmin ? grow50pc : growmin; 8390 } 8391 newprev = prev == NULL ? alloc(prevsize) 8392 : vim_realloc(prev, prevsize); 8393 if (newprev == NULL) 8394 { 8395 do_outofmem_msg((long_u)prevsize); 8396 failed = TRUE; 8397 break; 8398 } 8399 prev = newprev; 8400 } 8401 /* Add the line part to end of "prev". */ 8402 mch_memmove(prev + prevlen, start, p - start); 8403 prevlen += (long)(p - start); 8404 } 8405 } /* while */ 8406 8407 /* 8408 * For a negative line count use only the lines at the end of the file, 8409 * free the rest. 8410 */ 8411 if (!failed && maxline < 0) 8412 while (cnt > -maxline) 8413 { 8414 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first); 8415 --cnt; 8416 } 8417 8418 if (failed) 8419 { 8420 list_free(rettv->vval.v_list); 8421 /* readfile doc says an empty list is returned on error */ 8422 rettv->vval.v_list = list_alloc(); 8423 } 8424 8425 vim_free(prev); 8426 fclose(fd); 8427 } 8428 8429 #if defined(FEAT_RELTIME) 8430 static int list2proftime(typval_T *arg, proftime_T *tm); 8431 8432 /* 8433 * Convert a List to proftime_T. 8434 * Return FAIL when there is something wrong. 8435 */ 8436 static int 8437 list2proftime(typval_T *arg, proftime_T *tm) 8438 { 8439 long n1, n2; 8440 int error = FALSE; 8441 8442 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL 8443 || arg->vval.v_list->lv_len != 2) 8444 return FAIL; 8445 n1 = list_find_nr(arg->vval.v_list, 0L, &error); 8446 n2 = list_find_nr(arg->vval.v_list, 1L, &error); 8447 # ifdef WIN3264 8448 tm->HighPart = n1; 8449 tm->LowPart = n2; 8450 # else 8451 tm->tv_sec = n1; 8452 tm->tv_usec = n2; 8453 # endif 8454 return error ? FAIL : OK; 8455 } 8456 #endif /* FEAT_RELTIME */ 8457 8458 /* 8459 * "reltime()" function 8460 */ 8461 static void 8462 f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 8463 { 8464 #ifdef FEAT_RELTIME 8465 proftime_T res; 8466 proftime_T start; 8467 8468 if (argvars[0].v_type == VAR_UNKNOWN) 8469 { 8470 /* No arguments: get current time. */ 8471 profile_start(&res); 8472 } 8473 else if (argvars[1].v_type == VAR_UNKNOWN) 8474 { 8475 if (list2proftime(&argvars[0], &res) == FAIL) 8476 return; 8477 profile_end(&res); 8478 } 8479 else 8480 { 8481 /* Two arguments: compute the difference. */ 8482 if (list2proftime(&argvars[0], &start) == FAIL 8483 || list2proftime(&argvars[1], &res) == FAIL) 8484 return; 8485 profile_sub(&res, &start); 8486 } 8487 8488 if (rettv_list_alloc(rettv) == OK) 8489 { 8490 long n1, n2; 8491 8492 # ifdef WIN3264 8493 n1 = res.HighPart; 8494 n2 = res.LowPart; 8495 # else 8496 n1 = res.tv_sec; 8497 n2 = res.tv_usec; 8498 # endif 8499 list_append_number(rettv->vval.v_list, (varnumber_T)n1); 8500 list_append_number(rettv->vval.v_list, (varnumber_T)n2); 8501 } 8502 #endif 8503 } 8504 8505 #ifdef FEAT_FLOAT 8506 /* 8507 * "reltimefloat()" function 8508 */ 8509 static void 8510 f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv) 8511 { 8512 # ifdef FEAT_RELTIME 8513 proftime_T tm; 8514 # endif 8515 8516 rettv->v_type = VAR_FLOAT; 8517 rettv->vval.v_float = 0; 8518 # ifdef FEAT_RELTIME 8519 if (list2proftime(&argvars[0], &tm) == OK) 8520 rettv->vval.v_float = profile_float(&tm); 8521 # endif 8522 } 8523 #endif 8524 8525 /* 8526 * "reltimestr()" function 8527 */ 8528 static void 8529 f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv) 8530 { 8531 #ifdef FEAT_RELTIME 8532 proftime_T tm; 8533 #endif 8534 8535 rettv->v_type = VAR_STRING; 8536 rettv->vval.v_string = NULL; 8537 #ifdef FEAT_RELTIME 8538 if (list2proftime(&argvars[0], &tm) == OK) 8539 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm)); 8540 #endif 8541 } 8542 8543 #if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) 8544 static void make_connection(void); 8545 static int check_connection(void); 8546 8547 static void 8548 make_connection(void) 8549 { 8550 if (X_DISPLAY == NULL 8551 # ifdef FEAT_GUI 8552 && !gui.in_use 8553 # endif 8554 ) 8555 { 8556 x_force_connect = TRUE; 8557 setup_term_clip(); 8558 x_force_connect = FALSE; 8559 } 8560 } 8561 8562 static int 8563 check_connection(void) 8564 { 8565 make_connection(); 8566 if (X_DISPLAY == NULL) 8567 { 8568 EMSG(_("E240: No connection to the X server")); 8569 return FAIL; 8570 } 8571 return OK; 8572 } 8573 #endif 8574 8575 #ifdef FEAT_CLIENTSERVER 8576 static void 8577 remote_common(typval_T *argvars, typval_T *rettv, int expr) 8578 { 8579 char_u *server_name; 8580 char_u *keys; 8581 char_u *r = NULL; 8582 char_u buf[NUMBUFLEN]; 8583 int timeout = 0; 8584 # ifdef WIN32 8585 HWND w; 8586 # else 8587 Window w; 8588 # endif 8589 8590 if (check_restricted() || check_secure()) 8591 return; 8592 8593 # ifdef FEAT_X11 8594 if (check_connection() == FAIL) 8595 return; 8596 # endif 8597 if (argvars[2].v_type != VAR_UNKNOWN 8598 && argvars[3].v_type != VAR_UNKNOWN) 8599 timeout = get_tv_number(&argvars[3]); 8600 8601 server_name = get_tv_string_chk(&argvars[0]); 8602 if (server_name == NULL) 8603 return; /* type error; errmsg already given */ 8604 keys = get_tv_string_buf(&argvars[1], buf); 8605 # ifdef WIN32 8606 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0) 8607 # else 8608 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout, 8609 0, TRUE) < 0) 8610 # endif 8611 { 8612 if (r != NULL) 8613 EMSG(r); /* sending worked but evaluation failed */ 8614 else 8615 EMSG2(_("E241: Unable to send to %s"), server_name); 8616 return; 8617 } 8618 8619 rettv->vval.v_string = r; 8620 8621 if (argvars[2].v_type != VAR_UNKNOWN) 8622 { 8623 dictitem_T v; 8624 char_u str[30]; 8625 char_u *idvar; 8626 8627 idvar = get_tv_string_chk(&argvars[2]); 8628 if (idvar != NULL && *idvar != NUL) 8629 { 8630 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w); 8631 v.di_tv.v_type = VAR_STRING; 8632 v.di_tv.vval.v_string = vim_strsave(str); 8633 set_var(idvar, &v.di_tv, FALSE); 8634 vim_free(v.di_tv.vval.v_string); 8635 } 8636 } 8637 } 8638 #endif 8639 8640 /* 8641 * "remote_expr()" function 8642 */ 8643 static void 8644 f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv) 8645 { 8646 rettv->v_type = VAR_STRING; 8647 rettv->vval.v_string = NULL; 8648 #ifdef FEAT_CLIENTSERVER 8649 remote_common(argvars, rettv, TRUE); 8650 #endif 8651 } 8652 8653 /* 8654 * "remote_foreground()" function 8655 */ 8656 static void 8657 f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 8658 { 8659 #ifdef FEAT_CLIENTSERVER 8660 # ifdef WIN32 8661 /* On Win32 it's done in this application. */ 8662 { 8663 char_u *server_name = get_tv_string_chk(&argvars[0]); 8664 8665 if (server_name != NULL) 8666 serverForeground(server_name); 8667 } 8668 # else 8669 /* Send a foreground() expression to the server. */ 8670 argvars[1].v_type = VAR_STRING; 8671 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()"); 8672 argvars[2].v_type = VAR_UNKNOWN; 8673 remote_common(argvars, rettv, TRUE); 8674 vim_free(argvars[1].vval.v_string); 8675 # endif 8676 #endif 8677 } 8678 8679 static void 8680 f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv) 8681 { 8682 #ifdef FEAT_CLIENTSERVER 8683 dictitem_T v; 8684 char_u *s = NULL; 8685 # ifdef WIN32 8686 long_u n = 0; 8687 # endif 8688 char_u *serverid; 8689 8690 if (check_restricted() || check_secure()) 8691 { 8692 rettv->vval.v_number = -1; 8693 return; 8694 } 8695 serverid = get_tv_string_chk(&argvars[0]); 8696 if (serverid == NULL) 8697 { 8698 rettv->vval.v_number = -1; 8699 return; /* type error; errmsg already given */ 8700 } 8701 # ifdef WIN32 8702 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n); 8703 if (n == 0) 8704 rettv->vval.v_number = -1; 8705 else 8706 { 8707 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0); 8708 rettv->vval.v_number = (s != NULL); 8709 } 8710 # else 8711 if (check_connection() == FAIL) 8712 return; 8713 8714 rettv->vval.v_number = serverPeekReply(X_DISPLAY, 8715 serverStrToWin(serverid), &s); 8716 # endif 8717 8718 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0) 8719 { 8720 char_u *retvar; 8721 8722 v.di_tv.v_type = VAR_STRING; 8723 v.di_tv.vval.v_string = vim_strsave(s); 8724 retvar = get_tv_string_chk(&argvars[1]); 8725 if (retvar != NULL) 8726 set_var(retvar, &v.di_tv, FALSE); 8727 vim_free(v.di_tv.vval.v_string); 8728 } 8729 #else 8730 rettv->vval.v_number = -1; 8731 #endif 8732 } 8733 8734 static void 8735 f_remote_read(typval_T *argvars UNUSED, typval_T *rettv) 8736 { 8737 char_u *r = NULL; 8738 8739 #ifdef FEAT_CLIENTSERVER 8740 char_u *serverid = get_tv_string_chk(&argvars[0]); 8741 8742 if (serverid != NULL && !check_restricted() && !check_secure()) 8743 { 8744 int timeout = 0; 8745 # ifdef WIN32 8746 /* The server's HWND is encoded in the 'id' parameter */ 8747 long_u n = 0; 8748 # endif 8749 8750 if (argvars[1].v_type != VAR_UNKNOWN) 8751 timeout = get_tv_number(&argvars[1]); 8752 8753 # ifdef WIN32 8754 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n); 8755 if (n != 0) 8756 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout); 8757 if (r == NULL) 8758 # else 8759 if (check_connection() == FAIL 8760 || serverReadReply(X_DISPLAY, serverStrToWin(serverid), 8761 &r, FALSE, timeout) < 0) 8762 # endif 8763 EMSG(_("E277: Unable to read a server reply")); 8764 } 8765 #endif 8766 rettv->v_type = VAR_STRING; 8767 rettv->vval.v_string = r; 8768 } 8769 8770 /* 8771 * "remote_send()" function 8772 */ 8773 static void 8774 f_remote_send(typval_T *argvars UNUSED, typval_T *rettv) 8775 { 8776 rettv->v_type = VAR_STRING; 8777 rettv->vval.v_string = NULL; 8778 #ifdef FEAT_CLIENTSERVER 8779 remote_common(argvars, rettv, FALSE); 8780 #endif 8781 } 8782 8783 /* 8784 * "remote_startserver()" function 8785 */ 8786 static void 8787 f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 8788 { 8789 #ifdef FEAT_CLIENTSERVER 8790 char_u *server = get_tv_string_chk(&argvars[0]); 8791 8792 if (server == NULL) 8793 return; /* type error; errmsg already given */ 8794 if (serverName != NULL) 8795 EMSG(_("E941: already started a server")); 8796 else 8797 { 8798 # ifdef FEAT_X11 8799 if (check_connection() == OK) 8800 serverRegisterName(X_DISPLAY, server); 8801 # else 8802 serverSetName(server); 8803 # endif 8804 } 8805 #else 8806 EMSG(_("E942: +clientserver feature not available")); 8807 #endif 8808 } 8809 8810 /* 8811 * "remove()" function 8812 */ 8813 static void 8814 f_remove(typval_T *argvars, typval_T *rettv) 8815 { 8816 list_T *l; 8817 listitem_T *item, *item2; 8818 listitem_T *li; 8819 long idx; 8820 long end; 8821 char_u *key; 8822 dict_T *d; 8823 dictitem_T *di; 8824 char_u *arg_errmsg = (char_u *)N_("remove() argument"); 8825 8826 if (argvars[0].v_type == VAR_DICT) 8827 { 8828 if (argvars[2].v_type != VAR_UNKNOWN) 8829 EMSG2(_(e_toomanyarg), "remove()"); 8830 else if ((d = argvars[0].vval.v_dict) != NULL 8831 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE)) 8832 { 8833 key = get_tv_string_chk(&argvars[1]); 8834 if (key != NULL) 8835 { 8836 di = dict_find(d, key, -1); 8837 if (di == NULL) 8838 EMSG2(_(e_dictkey), key); 8839 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE) 8840 && !var_check_ro(di->di_flags, arg_errmsg, TRUE)) 8841 { 8842 *rettv = di->di_tv; 8843 init_tv(&di->di_tv); 8844 dictitem_remove(d, di); 8845 } 8846 } 8847 } 8848 } 8849 else if (argvars[0].v_type != VAR_LIST) 8850 EMSG2(_(e_listdictarg), "remove()"); 8851 else if ((l = argvars[0].vval.v_list) != NULL 8852 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE)) 8853 { 8854 int error = FALSE; 8855 8856 idx = (long)get_tv_number_chk(&argvars[1], &error); 8857 if (error) 8858 ; /* type error: do nothing, errmsg already given */ 8859 else if ((item = list_find(l, idx)) == NULL) 8860 EMSGN(_(e_listidx), idx); 8861 else 8862 { 8863 if (argvars[2].v_type == VAR_UNKNOWN) 8864 { 8865 /* Remove one item, return its value. */ 8866 vimlist_remove(l, item, item); 8867 *rettv = item->li_tv; 8868 vim_free(item); 8869 } 8870 else 8871 { 8872 /* Remove range of items, return list with values. */ 8873 end = (long)get_tv_number_chk(&argvars[2], &error); 8874 if (error) 8875 ; /* type error: do nothing */ 8876 else if ((item2 = list_find(l, end)) == NULL) 8877 EMSGN(_(e_listidx), end); 8878 else 8879 { 8880 int cnt = 0; 8881 8882 for (li = item; li != NULL; li = li->li_next) 8883 { 8884 ++cnt; 8885 if (li == item2) 8886 break; 8887 } 8888 if (li == NULL) /* didn't find "item2" after "item" */ 8889 EMSG(_(e_invrange)); 8890 else 8891 { 8892 vimlist_remove(l, item, item2); 8893 if (rettv_list_alloc(rettv) == OK) 8894 { 8895 l = rettv->vval.v_list; 8896 l->lv_first = item; 8897 l->lv_last = item2; 8898 item->li_prev = NULL; 8899 item2->li_next = NULL; 8900 l->lv_len = cnt; 8901 } 8902 } 8903 } 8904 } 8905 } 8906 } 8907 } 8908 8909 /* 8910 * "rename({from}, {to})" function 8911 */ 8912 static void 8913 f_rename(typval_T *argvars, typval_T *rettv) 8914 { 8915 char_u buf[NUMBUFLEN]; 8916 8917 if (check_restricted() || check_secure()) 8918 rettv->vval.v_number = -1; 8919 else 8920 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]), 8921 get_tv_string_buf(&argvars[1], buf)); 8922 } 8923 8924 /* 8925 * "repeat()" function 8926 */ 8927 static void 8928 f_repeat(typval_T *argvars, typval_T *rettv) 8929 { 8930 char_u *p; 8931 int n; 8932 int slen; 8933 int len; 8934 char_u *r; 8935 int i; 8936 8937 n = (int)get_tv_number(&argvars[1]); 8938 if (argvars[0].v_type == VAR_LIST) 8939 { 8940 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL) 8941 while (n-- > 0) 8942 if (list_extend(rettv->vval.v_list, 8943 argvars[0].vval.v_list, NULL) == FAIL) 8944 break; 8945 } 8946 else 8947 { 8948 p = get_tv_string(&argvars[0]); 8949 rettv->v_type = VAR_STRING; 8950 rettv->vval.v_string = NULL; 8951 8952 slen = (int)STRLEN(p); 8953 len = slen * n; 8954 if (len <= 0) 8955 return; 8956 8957 r = alloc(len + 1); 8958 if (r != NULL) 8959 { 8960 for (i = 0; i < n; i++) 8961 mch_memmove(r + i * slen, p, (size_t)slen); 8962 r[len] = NUL; 8963 } 8964 8965 rettv->vval.v_string = r; 8966 } 8967 } 8968 8969 /* 8970 * "resolve()" function 8971 */ 8972 static void 8973 f_resolve(typval_T *argvars, typval_T *rettv) 8974 { 8975 char_u *p; 8976 #ifdef HAVE_READLINK 8977 char_u *buf = NULL; 8978 #endif 8979 8980 p = get_tv_string(&argvars[0]); 8981 #ifdef FEAT_SHORTCUT 8982 { 8983 char_u *v = NULL; 8984 8985 v = mch_resolve_shortcut(p); 8986 if (v != NULL) 8987 rettv->vval.v_string = v; 8988 else 8989 rettv->vval.v_string = vim_strsave(p); 8990 } 8991 #else 8992 # ifdef HAVE_READLINK 8993 { 8994 char_u *cpy; 8995 int len; 8996 char_u *remain = NULL; 8997 char_u *q; 8998 int is_relative_to_current = FALSE; 8999 int has_trailing_pathsep = FALSE; 9000 int limit = 100; 9001 9002 p = vim_strsave(p); 9003 9004 if (p[0] == '.' && (vim_ispathsep(p[1]) 9005 || (p[1] == '.' && (vim_ispathsep(p[2]))))) 9006 is_relative_to_current = TRUE; 9007 9008 len = STRLEN(p); 9009 if (len > 0 && after_pathsep(p, p + len)) 9010 { 9011 has_trailing_pathsep = TRUE; 9012 p[len - 1] = NUL; /* the trailing slash breaks readlink() */ 9013 } 9014 9015 q = getnextcomp(p); 9016 if (*q != NUL) 9017 { 9018 /* Separate the first path component in "p", and keep the 9019 * remainder (beginning with the path separator). */ 9020 remain = vim_strsave(q - 1); 9021 q[-1] = NUL; 9022 } 9023 9024 buf = alloc(MAXPATHL + 1); 9025 if (buf == NULL) 9026 goto fail; 9027 9028 for (;;) 9029 { 9030 for (;;) 9031 { 9032 len = readlink((char *)p, (char *)buf, MAXPATHL); 9033 if (len <= 0) 9034 break; 9035 buf[len] = NUL; 9036 9037 if (limit-- == 0) 9038 { 9039 vim_free(p); 9040 vim_free(remain); 9041 EMSG(_("E655: Too many symbolic links (cycle?)")); 9042 rettv->vval.v_string = NULL; 9043 goto fail; 9044 } 9045 9046 /* Ensure that the result will have a trailing path separator 9047 * if the argument has one. */ 9048 if (remain == NULL && has_trailing_pathsep) 9049 add_pathsep(buf); 9050 9051 /* Separate the first path component in the link value and 9052 * concatenate the remainders. */ 9053 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf); 9054 if (*q != NUL) 9055 { 9056 if (remain == NULL) 9057 remain = vim_strsave(q - 1); 9058 else 9059 { 9060 cpy = concat_str(q - 1, remain); 9061 if (cpy != NULL) 9062 { 9063 vim_free(remain); 9064 remain = cpy; 9065 } 9066 } 9067 q[-1] = NUL; 9068 } 9069 9070 q = gettail(p); 9071 if (q > p && *q == NUL) 9072 { 9073 /* Ignore trailing path separator. */ 9074 q[-1] = NUL; 9075 q = gettail(p); 9076 } 9077 if (q > p && !mch_isFullName(buf)) 9078 { 9079 /* symlink is relative to directory of argument */ 9080 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1)); 9081 if (cpy != NULL) 9082 { 9083 STRCPY(cpy, p); 9084 STRCPY(gettail(cpy), buf); 9085 vim_free(p); 9086 p = cpy; 9087 } 9088 } 9089 else 9090 { 9091 vim_free(p); 9092 p = vim_strsave(buf); 9093 } 9094 } 9095 9096 if (remain == NULL) 9097 break; 9098 9099 /* Append the first path component of "remain" to "p". */ 9100 q = getnextcomp(remain + 1); 9101 len = q - remain - (*q != NUL); 9102 cpy = vim_strnsave(p, STRLEN(p) + len); 9103 if (cpy != NULL) 9104 { 9105 STRNCAT(cpy, remain, len); 9106 vim_free(p); 9107 p = cpy; 9108 } 9109 /* Shorten "remain". */ 9110 if (*q != NUL) 9111 STRMOVE(remain, q - 1); 9112 else 9113 { 9114 vim_free(remain); 9115 remain = NULL; 9116 } 9117 } 9118 9119 /* If the result is a relative path name, make it explicitly relative to 9120 * the current directory if and only if the argument had this form. */ 9121 if (!vim_ispathsep(*p)) 9122 { 9123 if (is_relative_to_current 9124 && *p != NUL 9125 && !(p[0] == '.' 9126 && (p[1] == NUL 9127 || vim_ispathsep(p[1]) 9128 || (p[1] == '.' 9129 && (p[2] == NUL 9130 || vim_ispathsep(p[2])))))) 9131 { 9132 /* Prepend "./". */ 9133 cpy = concat_str((char_u *)"./", p); 9134 if (cpy != NULL) 9135 { 9136 vim_free(p); 9137 p = cpy; 9138 } 9139 } 9140 else if (!is_relative_to_current) 9141 { 9142 /* Strip leading "./". */ 9143 q = p; 9144 while (q[0] == '.' && vim_ispathsep(q[1])) 9145 q += 2; 9146 if (q > p) 9147 STRMOVE(p, p + 2); 9148 } 9149 } 9150 9151 /* Ensure that the result will have no trailing path separator 9152 * if the argument had none. But keep "/" or "//". */ 9153 if (!has_trailing_pathsep) 9154 { 9155 q = p + STRLEN(p); 9156 if (after_pathsep(p, q)) 9157 *gettail_sep(p) = NUL; 9158 } 9159 9160 rettv->vval.v_string = p; 9161 } 9162 # else 9163 rettv->vval.v_string = vim_strsave(p); 9164 # endif 9165 #endif 9166 9167 simplify_filename(rettv->vval.v_string); 9168 9169 #ifdef HAVE_READLINK 9170 fail: 9171 vim_free(buf); 9172 #endif 9173 rettv->v_type = VAR_STRING; 9174 } 9175 9176 /* 9177 * "reverse({list})" function 9178 */ 9179 static void 9180 f_reverse(typval_T *argvars, typval_T *rettv) 9181 { 9182 list_T *l; 9183 listitem_T *li, *ni; 9184 9185 if (argvars[0].v_type != VAR_LIST) 9186 EMSG2(_(e_listarg), "reverse()"); 9187 else if ((l = argvars[0].vval.v_list) != NULL 9188 && !tv_check_lock(l->lv_lock, 9189 (char_u *)N_("reverse() argument"), TRUE)) 9190 { 9191 li = l->lv_last; 9192 l->lv_first = l->lv_last = NULL; 9193 l->lv_len = 0; 9194 while (li != NULL) 9195 { 9196 ni = li->li_prev; 9197 list_append(l, li); 9198 li = ni; 9199 } 9200 rettv_list_set(rettv, l); 9201 l->lv_idx = l->lv_len - l->lv_idx - 1; 9202 } 9203 } 9204 9205 #define SP_NOMOVE 0x01 /* don't move cursor */ 9206 #define SP_REPEAT 0x02 /* repeat to find outer pair */ 9207 #define SP_RETCOUNT 0x04 /* return matchcount */ 9208 #define SP_SETPCMARK 0x08 /* set previous context mark */ 9209 #define SP_START 0x10 /* accept match at start position */ 9210 #define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */ 9211 #define SP_END 0x40 /* leave cursor at end of match */ 9212 #define SP_COLUMN 0x80 /* start at cursor column */ 9213 9214 static int get_search_arg(typval_T *varp, int *flagsp); 9215 9216 /* 9217 * Get flags for a search function. 9218 * Possibly sets "p_ws". 9219 * Returns BACKWARD, FORWARD or zero (for an error). 9220 */ 9221 static int 9222 get_search_arg(typval_T *varp, int *flagsp) 9223 { 9224 int dir = FORWARD; 9225 char_u *flags; 9226 char_u nbuf[NUMBUFLEN]; 9227 int mask; 9228 9229 if (varp->v_type != VAR_UNKNOWN) 9230 { 9231 flags = get_tv_string_buf_chk(varp, nbuf); 9232 if (flags == NULL) 9233 return 0; /* type error; errmsg already given */ 9234 while (*flags != NUL) 9235 { 9236 switch (*flags) 9237 { 9238 case 'b': dir = BACKWARD; break; 9239 case 'w': p_ws = TRUE; break; 9240 case 'W': p_ws = FALSE; break; 9241 default: mask = 0; 9242 if (flagsp != NULL) 9243 switch (*flags) 9244 { 9245 case 'c': mask = SP_START; break; 9246 case 'e': mask = SP_END; break; 9247 case 'm': mask = SP_RETCOUNT; break; 9248 case 'n': mask = SP_NOMOVE; break; 9249 case 'p': mask = SP_SUBPAT; break; 9250 case 'r': mask = SP_REPEAT; break; 9251 case 's': mask = SP_SETPCMARK; break; 9252 case 'z': mask = SP_COLUMN; break; 9253 } 9254 if (mask == 0) 9255 { 9256 EMSG2(_(e_invarg2), flags); 9257 dir = 0; 9258 } 9259 else 9260 *flagsp |= mask; 9261 } 9262 if (dir == 0) 9263 break; 9264 ++flags; 9265 } 9266 } 9267 return dir; 9268 } 9269 9270 /* 9271 * Shared by search() and searchpos() functions. 9272 */ 9273 static int 9274 search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) 9275 { 9276 int flags; 9277 char_u *pat; 9278 pos_T pos; 9279 pos_T save_cursor; 9280 int save_p_ws = p_ws; 9281 int dir; 9282 int retval = 0; /* default: FAIL */ 9283 long lnum_stop = 0; 9284 proftime_T tm; 9285 #ifdef FEAT_RELTIME 9286 long time_limit = 0; 9287 #endif 9288 int options = SEARCH_KEEP; 9289 int subpatnum; 9290 9291 pat = get_tv_string(&argvars[0]); 9292 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */ 9293 if (dir == 0) 9294 goto theend; 9295 flags = *flagsp; 9296 if (flags & SP_START) 9297 options |= SEARCH_START; 9298 if (flags & SP_END) 9299 options |= SEARCH_END; 9300 if (flags & SP_COLUMN) 9301 options |= SEARCH_COL; 9302 9303 /* Optional arguments: line number to stop searching and timeout. */ 9304 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) 9305 { 9306 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL); 9307 if (lnum_stop < 0) 9308 goto theend; 9309 #ifdef FEAT_RELTIME 9310 if (argvars[3].v_type != VAR_UNKNOWN) 9311 { 9312 time_limit = (long)get_tv_number_chk(&argvars[3], NULL); 9313 if (time_limit < 0) 9314 goto theend; 9315 } 9316 #endif 9317 } 9318 9319 #ifdef FEAT_RELTIME 9320 /* Set the time limit, if there is one. */ 9321 profile_setlimit(time_limit, &tm); 9322 #endif 9323 9324 /* 9325 * This function does not accept SP_REPEAT and SP_RETCOUNT flags. 9326 * Check to make sure only those flags are set. 9327 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both 9328 * flags cannot be set. Check for that condition also. 9329 */ 9330 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0) 9331 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) 9332 { 9333 EMSG2(_(e_invarg2), get_tv_string(&argvars[1])); 9334 goto theend; 9335 } 9336 9337 pos = save_cursor = curwin->w_cursor; 9338 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L, 9339 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL); 9340 if (subpatnum != FAIL) 9341 { 9342 if (flags & SP_SUBPAT) 9343 retval = subpatnum; 9344 else 9345 retval = pos.lnum; 9346 if (flags & SP_SETPCMARK) 9347 setpcmark(); 9348 curwin->w_cursor = pos; 9349 if (match_pos != NULL) 9350 { 9351 /* Store the match cursor position */ 9352 match_pos->lnum = pos.lnum; 9353 match_pos->col = pos.col + 1; 9354 } 9355 /* "/$" will put the cursor after the end of the line, may need to 9356 * correct that here */ 9357 check_cursor(); 9358 } 9359 9360 /* If 'n' flag is used: restore cursor position. */ 9361 if (flags & SP_NOMOVE) 9362 curwin->w_cursor = save_cursor; 9363 else 9364 curwin->w_set_curswant = TRUE; 9365 theend: 9366 p_ws = save_p_ws; 9367 9368 return retval; 9369 } 9370 9371 #ifdef FEAT_FLOAT 9372 9373 /* 9374 * round() is not in C90, use ceil() or floor() instead. 9375 */ 9376 float_T 9377 vim_round(float_T f) 9378 { 9379 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5); 9380 } 9381 9382 /* 9383 * "round({float})" function 9384 */ 9385 static void 9386 f_round(typval_T *argvars, typval_T *rettv) 9387 { 9388 float_T f = 0.0; 9389 9390 rettv->v_type = VAR_FLOAT; 9391 if (get_float_arg(argvars, &f) == OK) 9392 rettv->vval.v_float = vim_round(f); 9393 else 9394 rettv->vval.v_float = 0.0; 9395 } 9396 #endif 9397 9398 /* 9399 * "screenattr()" function 9400 */ 9401 static void 9402 f_screenattr(typval_T *argvars, typval_T *rettv) 9403 { 9404 int row; 9405 int col; 9406 int c; 9407 9408 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1; 9409 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1; 9410 if (row < 0 || row >= screen_Rows 9411 || col < 0 || col >= screen_Columns) 9412 c = -1; 9413 else 9414 c = ScreenAttrs[LineOffset[row] + col]; 9415 rettv->vval.v_number = c; 9416 } 9417 9418 /* 9419 * "screenchar()" function 9420 */ 9421 static void 9422 f_screenchar(typval_T *argvars, typval_T *rettv) 9423 { 9424 int row; 9425 int col; 9426 int off; 9427 int c; 9428 9429 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1; 9430 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1; 9431 if (row < 0 || row >= screen_Rows 9432 || col < 0 || col >= screen_Columns) 9433 c = -1; 9434 else 9435 { 9436 off = LineOffset[row] + col; 9437 #ifdef FEAT_MBYTE 9438 if (enc_utf8 && ScreenLinesUC[off] != 0) 9439 c = ScreenLinesUC[off]; 9440 else 9441 #endif 9442 c = ScreenLines[off]; 9443 } 9444 rettv->vval.v_number = c; 9445 } 9446 9447 /* 9448 * "screencol()" function 9449 * 9450 * First column is 1 to be consistent with virtcol(). 9451 */ 9452 static void 9453 f_screencol(typval_T *argvars UNUSED, typval_T *rettv) 9454 { 9455 rettv->vval.v_number = screen_screencol() + 1; 9456 } 9457 9458 /* 9459 * "screenrow()" function 9460 */ 9461 static void 9462 f_screenrow(typval_T *argvars UNUSED, typval_T *rettv) 9463 { 9464 rettv->vval.v_number = screen_screenrow() + 1; 9465 } 9466 9467 /* 9468 * "search()" function 9469 */ 9470 static void 9471 f_search(typval_T *argvars, typval_T *rettv) 9472 { 9473 int flags = 0; 9474 9475 rettv->vval.v_number = search_cmn(argvars, NULL, &flags); 9476 } 9477 9478 /* 9479 * "searchdecl()" function 9480 */ 9481 static void 9482 f_searchdecl(typval_T *argvars, typval_T *rettv) 9483 { 9484 int locally = 1; 9485 int thisblock = 0; 9486 int error = FALSE; 9487 char_u *name; 9488 9489 rettv->vval.v_number = 1; /* default: FAIL */ 9490 9491 name = get_tv_string_chk(&argvars[0]); 9492 if (argvars[1].v_type != VAR_UNKNOWN) 9493 { 9494 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0; 9495 if (!error && argvars[2].v_type != VAR_UNKNOWN) 9496 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0; 9497 } 9498 if (!error && name != NULL) 9499 rettv->vval.v_number = find_decl(name, (int)STRLEN(name), 9500 locally, thisblock, SEARCH_KEEP) == FAIL; 9501 } 9502 9503 /* 9504 * Used by searchpair() and searchpairpos() 9505 */ 9506 static int 9507 searchpair_cmn(typval_T *argvars, pos_T *match_pos) 9508 { 9509 char_u *spat, *mpat, *epat; 9510 char_u *skip; 9511 int save_p_ws = p_ws; 9512 int dir; 9513 int flags = 0; 9514 char_u nbuf1[NUMBUFLEN]; 9515 char_u nbuf2[NUMBUFLEN]; 9516 char_u nbuf3[NUMBUFLEN]; 9517 int retval = 0; /* default: FAIL */ 9518 long lnum_stop = 0; 9519 long time_limit = 0; 9520 9521 /* Get the three pattern arguments: start, middle, end. */ 9522 spat = get_tv_string_chk(&argvars[0]); 9523 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1); 9524 epat = get_tv_string_buf_chk(&argvars[2], nbuf2); 9525 if (spat == NULL || mpat == NULL || epat == NULL) 9526 goto theend; /* type error */ 9527 9528 /* Handle the optional fourth argument: flags */ 9529 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */ 9530 if (dir == 0) 9531 goto theend; 9532 9533 /* Don't accept SP_END or SP_SUBPAT. 9534 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set. 9535 */ 9536 if ((flags & (SP_END | SP_SUBPAT)) != 0 9537 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) 9538 { 9539 EMSG2(_(e_invarg2), get_tv_string(&argvars[3])); 9540 goto theend; 9541 } 9542 9543 /* Using 'r' implies 'W', otherwise it doesn't work. */ 9544 if (flags & SP_REPEAT) 9545 p_ws = FALSE; 9546 9547 /* Optional fifth argument: skip expression */ 9548 if (argvars[3].v_type == VAR_UNKNOWN 9549 || argvars[4].v_type == VAR_UNKNOWN) 9550 skip = (char_u *)""; 9551 else 9552 { 9553 skip = get_tv_string_buf_chk(&argvars[4], nbuf3); 9554 if (argvars[5].v_type != VAR_UNKNOWN) 9555 { 9556 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL); 9557 if (lnum_stop < 0) 9558 goto theend; 9559 #ifdef FEAT_RELTIME 9560 if (argvars[6].v_type != VAR_UNKNOWN) 9561 { 9562 time_limit = (long)get_tv_number_chk(&argvars[6], NULL); 9563 if (time_limit < 0) 9564 goto theend; 9565 } 9566 #endif 9567 } 9568 } 9569 if (skip == NULL) 9570 goto theend; /* type error */ 9571 9572 retval = do_searchpair(spat, mpat, epat, dir, skip, flags, 9573 match_pos, lnum_stop, time_limit); 9574 9575 theend: 9576 p_ws = save_p_ws; 9577 9578 return retval; 9579 } 9580 9581 /* 9582 * "searchpair()" function 9583 */ 9584 static void 9585 f_searchpair(typval_T *argvars, typval_T *rettv) 9586 { 9587 rettv->vval.v_number = searchpair_cmn(argvars, NULL); 9588 } 9589 9590 /* 9591 * "searchpairpos()" function 9592 */ 9593 static void 9594 f_searchpairpos(typval_T *argvars, typval_T *rettv) 9595 { 9596 pos_T match_pos; 9597 int lnum = 0; 9598 int col = 0; 9599 9600 if (rettv_list_alloc(rettv) == FAIL) 9601 return; 9602 9603 if (searchpair_cmn(argvars, &match_pos) > 0) 9604 { 9605 lnum = match_pos.lnum; 9606 col = match_pos.col; 9607 } 9608 9609 list_append_number(rettv->vval.v_list, (varnumber_T)lnum); 9610 list_append_number(rettv->vval.v_list, (varnumber_T)col); 9611 } 9612 9613 /* 9614 * Search for a start/middle/end thing. 9615 * Used by searchpair(), see its documentation for the details. 9616 * Returns 0 or -1 for no match, 9617 */ 9618 long 9619 do_searchpair( 9620 char_u *spat, /* start pattern */ 9621 char_u *mpat, /* middle pattern */ 9622 char_u *epat, /* end pattern */ 9623 int dir, /* BACKWARD or FORWARD */ 9624 char_u *skip, /* skip expression */ 9625 int flags, /* SP_SETPCMARK and other SP_ values */ 9626 pos_T *match_pos, 9627 linenr_T lnum_stop, /* stop at this line if not zero */ 9628 long time_limit UNUSED) /* stop after this many msec */ 9629 { 9630 char_u *save_cpo; 9631 char_u *pat, *pat2 = NULL, *pat3 = NULL; 9632 long retval = 0; 9633 pos_T pos; 9634 pos_T firstpos; 9635 pos_T foundpos; 9636 pos_T save_cursor; 9637 pos_T save_pos; 9638 int n; 9639 int r; 9640 int nest = 1; 9641 int err; 9642 int options = SEARCH_KEEP; 9643 proftime_T tm; 9644 9645 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ 9646 save_cpo = p_cpo; 9647 p_cpo = empty_option; 9648 9649 #ifdef FEAT_RELTIME 9650 /* Set the time limit, if there is one. */ 9651 profile_setlimit(time_limit, &tm); 9652 #endif 9653 9654 /* Make two search patterns: start/end (pat2, for in nested pairs) and 9655 * start/middle/end (pat3, for the top pair). */ 9656 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17)); 9657 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25)); 9658 if (pat2 == NULL || pat3 == NULL) 9659 goto theend; 9660 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat); 9661 if (*mpat == NUL) 9662 STRCPY(pat3, pat2); 9663 else 9664 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", 9665 spat, epat, mpat); 9666 if (flags & SP_START) 9667 options |= SEARCH_START; 9668 9669 save_cursor = curwin->w_cursor; 9670 pos = curwin->w_cursor; 9671 CLEAR_POS(&firstpos); 9672 CLEAR_POS(&foundpos); 9673 pat = pat3; 9674 for (;;) 9675 { 9676 n = searchit(curwin, curbuf, &pos, dir, pat, 1L, 9677 options, RE_SEARCH, lnum_stop, &tm, NULL); 9678 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))) 9679 /* didn't find it or found the first match again: FAIL */ 9680 break; 9681 9682 if (firstpos.lnum == 0) 9683 firstpos = pos; 9684 if (EQUAL_POS(pos, foundpos)) 9685 { 9686 /* Found the same position again. Can happen with a pattern that 9687 * has "\zs" at the end and searching backwards. Advance one 9688 * character and try again. */ 9689 if (dir == BACKWARD) 9690 decl(&pos); 9691 else 9692 incl(&pos); 9693 } 9694 foundpos = pos; 9695 9696 /* clear the start flag to avoid getting stuck here */ 9697 options &= ~SEARCH_START; 9698 9699 /* If the skip pattern matches, ignore this match. */ 9700 if (*skip != NUL) 9701 { 9702 save_pos = curwin->w_cursor; 9703 curwin->w_cursor = pos; 9704 r = eval_to_bool(skip, &err, NULL, FALSE); 9705 curwin->w_cursor = save_pos; 9706 if (err) 9707 { 9708 /* Evaluating {skip} caused an error, break here. */ 9709 curwin->w_cursor = save_cursor; 9710 retval = -1; 9711 break; 9712 } 9713 if (r) 9714 continue; 9715 } 9716 9717 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2)) 9718 { 9719 /* Found end when searching backwards or start when searching 9720 * forward: nested pair. */ 9721 ++nest; 9722 pat = pat2; /* nested, don't search for middle */ 9723 } 9724 else 9725 { 9726 /* Found end when searching forward or start when searching 9727 * backward: end of (nested) pair; or found middle in outer pair. */ 9728 if (--nest == 1) 9729 pat = pat3; /* outer level, search for middle */ 9730 } 9731 9732 if (nest == 0) 9733 { 9734 /* Found the match: return matchcount or line number. */ 9735 if (flags & SP_RETCOUNT) 9736 ++retval; 9737 else 9738 retval = pos.lnum; 9739 if (flags & SP_SETPCMARK) 9740 setpcmark(); 9741 curwin->w_cursor = pos; 9742 if (!(flags & SP_REPEAT)) 9743 break; 9744 nest = 1; /* search for next unmatched */ 9745 } 9746 } 9747 9748 if (match_pos != NULL) 9749 { 9750 /* Store the match cursor position */ 9751 match_pos->lnum = curwin->w_cursor.lnum; 9752 match_pos->col = curwin->w_cursor.col + 1; 9753 } 9754 9755 /* If 'n' flag is used or search failed: restore cursor position. */ 9756 if ((flags & SP_NOMOVE) || retval == 0) 9757 curwin->w_cursor = save_cursor; 9758 9759 theend: 9760 vim_free(pat2); 9761 vim_free(pat3); 9762 if (p_cpo == empty_option) 9763 p_cpo = save_cpo; 9764 else 9765 /* Darn, evaluating the {skip} expression changed the value. */ 9766 free_string_option(save_cpo); 9767 9768 return retval; 9769 } 9770 9771 /* 9772 * "searchpos()" function 9773 */ 9774 static void 9775 f_searchpos(typval_T *argvars, typval_T *rettv) 9776 { 9777 pos_T match_pos; 9778 int lnum = 0; 9779 int col = 0; 9780 int n; 9781 int flags = 0; 9782 9783 if (rettv_list_alloc(rettv) == FAIL) 9784 return; 9785 9786 n = search_cmn(argvars, &match_pos, &flags); 9787 if (n > 0) 9788 { 9789 lnum = match_pos.lnum; 9790 col = match_pos.col; 9791 } 9792 9793 list_append_number(rettv->vval.v_list, (varnumber_T)lnum); 9794 list_append_number(rettv->vval.v_list, (varnumber_T)col); 9795 if (flags & SP_SUBPAT) 9796 list_append_number(rettv->vval.v_list, (varnumber_T)n); 9797 } 9798 9799 static void 9800 f_server2client(typval_T *argvars UNUSED, typval_T *rettv) 9801 { 9802 #ifdef FEAT_CLIENTSERVER 9803 char_u buf[NUMBUFLEN]; 9804 char_u *server = get_tv_string_chk(&argvars[0]); 9805 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf); 9806 9807 rettv->vval.v_number = -1; 9808 if (server == NULL || reply == NULL) 9809 return; 9810 if (check_restricted() || check_secure()) 9811 return; 9812 # ifdef FEAT_X11 9813 if (check_connection() == FAIL) 9814 return; 9815 # endif 9816 9817 if (serverSendReply(server, reply) < 0) 9818 { 9819 EMSG(_("E258: Unable to send to client")); 9820 return; 9821 } 9822 rettv->vval.v_number = 0; 9823 #else 9824 rettv->vval.v_number = -1; 9825 #endif 9826 } 9827 9828 static void 9829 f_serverlist(typval_T *argvars UNUSED, typval_T *rettv) 9830 { 9831 char_u *r = NULL; 9832 9833 #ifdef FEAT_CLIENTSERVER 9834 # ifdef WIN32 9835 r = serverGetVimNames(); 9836 # else 9837 make_connection(); 9838 if (X_DISPLAY != NULL) 9839 r = serverGetVimNames(X_DISPLAY); 9840 # endif 9841 #endif 9842 rettv->v_type = VAR_STRING; 9843 rettv->vval.v_string = r; 9844 } 9845 9846 /* 9847 * "setbufvar()" function 9848 */ 9849 static void 9850 f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED) 9851 { 9852 buf_T *buf; 9853 char_u *varname, *bufvarname; 9854 typval_T *varp; 9855 char_u nbuf[NUMBUFLEN]; 9856 9857 if (check_restricted() || check_secure()) 9858 return; 9859 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ 9860 varname = get_tv_string_chk(&argvars[1]); 9861 buf = get_buf_tv(&argvars[0], FALSE); 9862 varp = &argvars[2]; 9863 9864 if (buf != NULL && varname != NULL && varp != NULL) 9865 { 9866 if (*varname == '&') 9867 { 9868 long numval; 9869 char_u *strval; 9870 int error = FALSE; 9871 aco_save_T aco; 9872 9873 /* set curbuf to be our buf, temporarily */ 9874 aucmd_prepbuf(&aco, buf); 9875 9876 ++varname; 9877 numval = (long)get_tv_number_chk(varp, &error); 9878 strval = get_tv_string_buf_chk(varp, nbuf); 9879 if (!error && strval != NULL) 9880 set_option_value(varname, numval, strval, OPT_LOCAL); 9881 9882 /* reset notion of buffer */ 9883 aucmd_restbuf(&aco); 9884 } 9885 else 9886 { 9887 buf_T *save_curbuf = curbuf; 9888 9889 bufvarname = alloc((unsigned)STRLEN(varname) + 3); 9890 if (bufvarname != NULL) 9891 { 9892 curbuf = buf; 9893 STRCPY(bufvarname, "b:"); 9894 STRCPY(bufvarname + 2, varname); 9895 set_var(bufvarname, varp, TRUE); 9896 vim_free(bufvarname); 9897 curbuf = save_curbuf; 9898 } 9899 } 9900 } 9901 } 9902 9903 static void 9904 f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED) 9905 { 9906 dict_T *d; 9907 dictitem_T *di; 9908 char_u *csearch; 9909 9910 if (argvars[0].v_type != VAR_DICT) 9911 { 9912 EMSG(_(e_dictreq)); 9913 return; 9914 } 9915 9916 if ((d = argvars[0].vval.v_dict) != NULL) 9917 { 9918 csearch = get_dict_string(d, (char_u *)"char", FALSE); 9919 if (csearch != NULL) 9920 { 9921 #ifdef FEAT_MBYTE 9922 if (enc_utf8) 9923 { 9924 int pcc[MAX_MCO]; 9925 int c = utfc_ptr2char(csearch, pcc); 9926 9927 set_last_csearch(c, csearch, utfc_ptr2len(csearch)); 9928 } 9929 else 9930 #endif 9931 set_last_csearch(PTR2CHAR(csearch), 9932 csearch, MB_PTR2LEN(csearch)); 9933 } 9934 9935 di = dict_find(d, (char_u *)"forward", -1); 9936 if (di != NULL) 9937 set_csearch_direction((int)get_tv_number(&di->di_tv) 9938 ? FORWARD : BACKWARD); 9939 9940 di = dict_find(d, (char_u *)"until", -1); 9941 if (di != NULL) 9942 set_csearch_until(!!get_tv_number(&di->di_tv)); 9943 } 9944 } 9945 9946 /* 9947 * "setcmdpos()" function 9948 */ 9949 static void 9950 f_setcmdpos(typval_T *argvars, typval_T *rettv) 9951 { 9952 int pos = (int)get_tv_number(&argvars[0]) - 1; 9953 9954 if (pos >= 0) 9955 rettv->vval.v_number = set_cmdline_pos(pos); 9956 } 9957 9958 /* 9959 * "setfperm({fname}, {mode})" function 9960 */ 9961 static void 9962 f_setfperm(typval_T *argvars, typval_T *rettv) 9963 { 9964 char_u *fname; 9965 char_u modebuf[NUMBUFLEN]; 9966 char_u *mode_str; 9967 int i; 9968 int mask; 9969 int mode = 0; 9970 9971 rettv->vval.v_number = 0; 9972 fname = get_tv_string_chk(&argvars[0]); 9973 if (fname == NULL) 9974 return; 9975 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf); 9976 if (mode_str == NULL) 9977 return; 9978 if (STRLEN(mode_str) != 9) 9979 { 9980 EMSG2(_(e_invarg2), mode_str); 9981 return; 9982 } 9983 9984 mask = 1; 9985 for (i = 8; i >= 0; --i) 9986 { 9987 if (mode_str[i] != '-') 9988 mode |= mask; 9989 mask = mask << 1; 9990 } 9991 rettv->vval.v_number = mch_setperm(fname, mode) == OK; 9992 } 9993 9994 /* 9995 * "setline()" function 9996 */ 9997 static void 9998 f_setline(typval_T *argvars, typval_T *rettv) 9999 { 10000 linenr_T lnum; 10001 char_u *line = NULL; 10002 list_T *l = NULL; 10003 listitem_T *li = NULL; 10004 long added = 0; 10005 linenr_T lcount = curbuf->b_ml.ml_line_count; 10006 10007 lnum = get_tv_lnum(&argvars[0]); 10008 if (argvars[1].v_type == VAR_LIST) 10009 { 10010 l = argvars[1].vval.v_list; 10011 li = l->lv_first; 10012 } 10013 else 10014 line = get_tv_string_chk(&argvars[1]); 10015 10016 /* default result is zero == OK */ 10017 for (;;) 10018 { 10019 if (l != NULL) 10020 { 10021 /* list argument, get next string */ 10022 if (li == NULL) 10023 break; 10024 line = get_tv_string_chk(&li->li_tv); 10025 li = li->li_next; 10026 } 10027 10028 rettv->vval.v_number = 1; /* FAIL */ 10029 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) 10030 break; 10031 10032 /* When coming here from Insert mode, sync undo, so that this can be 10033 * undone separately from what was previously inserted. */ 10034 if (u_sync_once == 2) 10035 { 10036 u_sync_once = 1; /* notify that u_sync() was called */ 10037 u_sync(TRUE); 10038 } 10039 10040 if (lnum <= curbuf->b_ml.ml_line_count) 10041 { 10042 /* existing line, replace it */ 10043 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK) 10044 { 10045 changed_bytes(lnum, 0); 10046 if (lnum == curwin->w_cursor.lnum) 10047 check_cursor_col(); 10048 rettv->vval.v_number = 0; /* OK */ 10049 } 10050 } 10051 else if (added > 0 || u_save(lnum - 1, lnum) == OK) 10052 { 10053 /* lnum is one past the last line, append the line */ 10054 ++added; 10055 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK) 10056 rettv->vval.v_number = 0; /* OK */ 10057 } 10058 10059 if (l == NULL) /* only one string argument */ 10060 break; 10061 ++lnum; 10062 } 10063 10064 if (added > 0) 10065 appended_lines_mark(lcount, added); 10066 } 10067 10068 static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *what_arg, typval_T *rettv); 10069 10070 /* 10071 * Used by "setqflist()" and "setloclist()" functions 10072 */ 10073 static void 10074 set_qf_ll_list( 10075 win_T *wp UNUSED, 10076 typval_T *list_arg UNUSED, 10077 typval_T *action_arg UNUSED, 10078 typval_T *what_arg UNUSED, 10079 typval_T *rettv) 10080 { 10081 #ifdef FEAT_QUICKFIX 10082 static char *e_invact = N_("E927: Invalid action: '%s'"); 10083 char_u *act; 10084 int action = 0; 10085 #endif 10086 10087 rettv->vval.v_number = -1; 10088 10089 #ifdef FEAT_QUICKFIX 10090 if (list_arg->v_type != VAR_LIST) 10091 EMSG(_(e_listreq)); 10092 else 10093 { 10094 list_T *l = list_arg->vval.v_list; 10095 dict_T *d = NULL; 10096 int valid_dict = TRUE; 10097 10098 if (action_arg->v_type == VAR_STRING) 10099 { 10100 act = get_tv_string_chk(action_arg); 10101 if (act == NULL) 10102 return; /* type error; errmsg already given */ 10103 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') && 10104 act[1] == NUL) 10105 action = *act; 10106 else 10107 EMSG2(_(e_invact), act); 10108 } 10109 else if (action_arg->v_type == VAR_UNKNOWN) 10110 action = ' '; 10111 else 10112 EMSG(_(e_stringreq)); 10113 10114 if (action_arg->v_type != VAR_UNKNOWN 10115 && what_arg->v_type != VAR_UNKNOWN) 10116 { 10117 if (what_arg->v_type == VAR_DICT) 10118 d = what_arg->vval.v_dict; 10119 else 10120 { 10121 EMSG(_(e_dictreq)); 10122 valid_dict = FALSE; 10123 } 10124 } 10125 10126 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action, 10127 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()"), d) == OK) 10128 rettv->vval.v_number = 0; 10129 } 10130 #endif 10131 } 10132 10133 /* 10134 * "setloclist()" function 10135 */ 10136 static void 10137 f_setloclist(typval_T *argvars, typval_T *rettv) 10138 { 10139 win_T *win; 10140 10141 rettv->vval.v_number = -1; 10142 10143 win = find_win_by_nr(&argvars[0], NULL); 10144 if (win != NULL) 10145 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv); 10146 } 10147 10148 /* 10149 * "setmatches()" function 10150 */ 10151 static void 10152 f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 10153 { 10154 #ifdef FEAT_SEARCH_EXTRA 10155 list_T *l; 10156 listitem_T *li; 10157 dict_T *d; 10158 list_T *s = NULL; 10159 10160 rettv->vval.v_number = -1; 10161 if (argvars[0].v_type != VAR_LIST) 10162 { 10163 EMSG(_(e_listreq)); 10164 return; 10165 } 10166 if ((l = argvars[0].vval.v_list) != NULL) 10167 { 10168 10169 /* To some extent make sure that we are dealing with a list from 10170 * "getmatches()". */ 10171 li = l->lv_first; 10172 while (li != NULL) 10173 { 10174 if (li->li_tv.v_type != VAR_DICT 10175 || (d = li->li_tv.vval.v_dict) == NULL) 10176 { 10177 EMSG(_(e_invarg)); 10178 return; 10179 } 10180 if (!(dict_find(d, (char_u *)"group", -1) != NULL 10181 && (dict_find(d, (char_u *)"pattern", -1) != NULL 10182 || dict_find(d, (char_u *)"pos1", -1) != NULL) 10183 && dict_find(d, (char_u *)"priority", -1) != NULL 10184 && dict_find(d, (char_u *)"id", -1) != NULL)) 10185 { 10186 EMSG(_(e_invarg)); 10187 return; 10188 } 10189 li = li->li_next; 10190 } 10191 10192 clear_matches(curwin); 10193 li = l->lv_first; 10194 while (li != NULL) 10195 { 10196 int i = 0; 10197 char_u buf[5]; 10198 dictitem_T *di; 10199 char_u *group; 10200 int priority; 10201 int id; 10202 char_u *conceal; 10203 10204 d = li->li_tv.vval.v_dict; 10205 if (dict_find(d, (char_u *)"pattern", -1) == NULL) 10206 { 10207 if (s == NULL) 10208 { 10209 s = list_alloc(); 10210 if (s == NULL) 10211 return; 10212 } 10213 10214 /* match from matchaddpos() */ 10215 for (i = 1; i < 9; i++) 10216 { 10217 sprintf((char *)buf, (char *)"pos%d", i); 10218 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL) 10219 { 10220 if (di->di_tv.v_type != VAR_LIST) 10221 return; 10222 10223 list_append_tv(s, &di->di_tv); 10224 s->lv_refcount++; 10225 } 10226 else 10227 break; 10228 } 10229 } 10230 10231 group = get_dict_string(d, (char_u *)"group", TRUE); 10232 priority = (int)get_dict_number(d, (char_u *)"priority"); 10233 id = (int)get_dict_number(d, (char_u *)"id"); 10234 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL 10235 ? get_dict_string(d, (char_u *)"conceal", TRUE) 10236 : NULL; 10237 if (i == 0) 10238 { 10239 match_add(curwin, group, 10240 get_dict_string(d, (char_u *)"pattern", FALSE), 10241 priority, id, NULL, conceal); 10242 } 10243 else 10244 { 10245 match_add(curwin, group, NULL, priority, id, s, conceal); 10246 list_unref(s); 10247 s = NULL; 10248 } 10249 vim_free(group); 10250 vim_free(conceal); 10251 10252 li = li->li_next; 10253 } 10254 rettv->vval.v_number = 0; 10255 } 10256 #endif 10257 } 10258 10259 /* 10260 * "setpos()" function 10261 */ 10262 static void 10263 f_setpos(typval_T *argvars, typval_T *rettv) 10264 { 10265 pos_T pos; 10266 int fnum; 10267 char_u *name; 10268 colnr_T curswant = -1; 10269 10270 rettv->vval.v_number = -1; 10271 name = get_tv_string_chk(argvars); 10272 if (name != NULL) 10273 { 10274 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK) 10275 { 10276 if (--pos.col < 0) 10277 pos.col = 0; 10278 if (name[0] == '.' && name[1] == NUL) 10279 { 10280 /* set cursor; "fnum" is ignored */ 10281 curwin->w_cursor = pos; 10282 if (curswant >= 0) 10283 { 10284 curwin->w_curswant = curswant - 1; 10285 curwin->w_set_curswant = FALSE; 10286 } 10287 check_cursor(); 10288 rettv->vval.v_number = 0; 10289 } 10290 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) 10291 { 10292 /* set mark */ 10293 if (setmark_pos(name[1], &pos, fnum) == OK) 10294 rettv->vval.v_number = 0; 10295 } 10296 else 10297 EMSG(_(e_invarg)); 10298 } 10299 } 10300 } 10301 10302 /* 10303 * "setqflist()" function 10304 */ 10305 static void 10306 f_setqflist(typval_T *argvars, typval_T *rettv) 10307 { 10308 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv); 10309 } 10310 10311 /* 10312 * "setreg()" function 10313 */ 10314 static void 10315 f_setreg(typval_T *argvars, typval_T *rettv) 10316 { 10317 int regname; 10318 char_u *strregname; 10319 char_u *stropt; 10320 char_u *strval; 10321 int append; 10322 char_u yank_type; 10323 long block_len; 10324 10325 block_len = -1; 10326 yank_type = MAUTO; 10327 append = FALSE; 10328 10329 strregname = get_tv_string_chk(argvars); 10330 rettv->vval.v_number = 1; /* FAIL is default */ 10331 10332 if (strregname == NULL) 10333 return; /* type error; errmsg already given */ 10334 regname = *strregname; 10335 if (regname == 0 || regname == '@') 10336 regname = '"'; 10337 10338 if (argvars[2].v_type != VAR_UNKNOWN) 10339 { 10340 stropt = get_tv_string_chk(&argvars[2]); 10341 if (stropt == NULL) 10342 return; /* type error */ 10343 for (; *stropt != NUL; ++stropt) 10344 switch (*stropt) 10345 { 10346 case 'a': case 'A': /* append */ 10347 append = TRUE; 10348 break; 10349 case 'v': case 'c': /* character-wise selection */ 10350 yank_type = MCHAR; 10351 break; 10352 case 'V': case 'l': /* line-wise selection */ 10353 yank_type = MLINE; 10354 break; 10355 case 'b': case Ctrl_V: /* block-wise selection */ 10356 yank_type = MBLOCK; 10357 if (VIM_ISDIGIT(stropt[1])) 10358 { 10359 ++stropt; 10360 block_len = getdigits(&stropt) - 1; 10361 --stropt; 10362 } 10363 break; 10364 } 10365 } 10366 10367 if (argvars[1].v_type == VAR_LIST) 10368 { 10369 char_u **lstval; 10370 char_u **allocval; 10371 char_u buf[NUMBUFLEN]; 10372 char_u **curval; 10373 char_u **curallocval; 10374 list_T *ll = argvars[1].vval.v_list; 10375 listitem_T *li; 10376 int len; 10377 10378 /* If the list is NULL handle like an empty list. */ 10379 len = ll == NULL ? 0 : ll->lv_len; 10380 10381 /* First half: use for pointers to result lines; second half: use for 10382 * pointers to allocated copies. */ 10383 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2)); 10384 if (lstval == NULL) 10385 return; 10386 curval = lstval; 10387 allocval = lstval + len + 2; 10388 curallocval = allocval; 10389 10390 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL; 10391 li = li->li_next) 10392 { 10393 strval = get_tv_string_buf_chk(&li->li_tv, buf); 10394 if (strval == NULL) 10395 goto free_lstval; 10396 if (strval == buf) 10397 { 10398 /* Need to make a copy, next get_tv_string_buf_chk() will 10399 * overwrite the string. */ 10400 strval = vim_strsave(buf); 10401 if (strval == NULL) 10402 goto free_lstval; 10403 *curallocval++ = strval; 10404 } 10405 *curval++ = strval; 10406 } 10407 *curval++ = NULL; 10408 10409 write_reg_contents_lst(regname, lstval, -1, 10410 append, yank_type, block_len); 10411 free_lstval: 10412 while (curallocval > allocval) 10413 vim_free(*--curallocval); 10414 vim_free(lstval); 10415 } 10416 else 10417 { 10418 strval = get_tv_string_chk(&argvars[1]); 10419 if (strval == NULL) 10420 return; 10421 write_reg_contents_ex(regname, strval, -1, 10422 append, yank_type, block_len); 10423 } 10424 rettv->vval.v_number = 0; 10425 } 10426 10427 /* 10428 * "settabvar()" function 10429 */ 10430 static void 10431 f_settabvar(typval_T *argvars, typval_T *rettv) 10432 { 10433 #ifdef FEAT_WINDOWS 10434 tabpage_T *save_curtab; 10435 tabpage_T *tp; 10436 #endif 10437 char_u *varname, *tabvarname; 10438 typval_T *varp; 10439 10440 rettv->vval.v_number = 0; 10441 10442 if (check_restricted() || check_secure()) 10443 return; 10444 10445 #ifdef FEAT_WINDOWS 10446 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); 10447 #endif 10448 varname = get_tv_string_chk(&argvars[1]); 10449 varp = &argvars[2]; 10450 10451 if (varname != NULL && varp != NULL 10452 #ifdef FEAT_WINDOWS 10453 && tp != NULL 10454 #endif 10455 ) 10456 { 10457 #ifdef FEAT_WINDOWS 10458 save_curtab = curtab; 10459 goto_tabpage_tp(tp, FALSE, FALSE); 10460 #endif 10461 10462 tabvarname = alloc((unsigned)STRLEN(varname) + 3); 10463 if (tabvarname != NULL) 10464 { 10465 STRCPY(tabvarname, "t:"); 10466 STRCPY(tabvarname + 2, varname); 10467 set_var(tabvarname, varp, TRUE); 10468 vim_free(tabvarname); 10469 } 10470 10471 #ifdef FEAT_WINDOWS 10472 /* Restore current tabpage */ 10473 if (valid_tabpage(save_curtab)) 10474 goto_tabpage_tp(save_curtab, FALSE, FALSE); 10475 #endif 10476 } 10477 } 10478 10479 /* 10480 * "settabwinvar()" function 10481 */ 10482 static void 10483 f_settabwinvar(typval_T *argvars, typval_T *rettv) 10484 { 10485 setwinvar(argvars, rettv, 1); 10486 } 10487 10488 /* 10489 * "setwinvar()" function 10490 */ 10491 static void 10492 f_setwinvar(typval_T *argvars, typval_T *rettv) 10493 { 10494 setwinvar(argvars, rettv, 0); 10495 } 10496 10497 #ifdef FEAT_CRYPT 10498 /* 10499 * "sha256({string})" function 10500 */ 10501 static void 10502 f_sha256(typval_T *argvars, typval_T *rettv) 10503 { 10504 char_u *p; 10505 10506 p = get_tv_string(&argvars[0]); 10507 rettv->vval.v_string = vim_strsave( 10508 sha256_bytes(p, (int)STRLEN(p), NULL, 0)); 10509 rettv->v_type = VAR_STRING; 10510 } 10511 #endif /* FEAT_CRYPT */ 10512 10513 /* 10514 * "shellescape({string})" function 10515 */ 10516 static void 10517 f_shellescape(typval_T *argvars, typval_T *rettv) 10518 { 10519 int do_special = non_zero_arg(&argvars[1]); 10520 10521 rettv->vval.v_string = vim_strsave_shellescape( 10522 get_tv_string(&argvars[0]), do_special, do_special); 10523 rettv->v_type = VAR_STRING; 10524 } 10525 10526 /* 10527 * shiftwidth() function 10528 */ 10529 static void 10530 f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv) 10531 { 10532 rettv->vval.v_number = get_sw_value(curbuf); 10533 } 10534 10535 /* 10536 * "simplify()" function 10537 */ 10538 static void 10539 f_simplify(typval_T *argvars, typval_T *rettv) 10540 { 10541 char_u *p; 10542 10543 p = get_tv_string(&argvars[0]); 10544 rettv->vval.v_string = vim_strsave(p); 10545 simplify_filename(rettv->vval.v_string); /* simplify in place */ 10546 rettv->v_type = VAR_STRING; 10547 } 10548 10549 #ifdef FEAT_FLOAT 10550 /* 10551 * "sin()" function 10552 */ 10553 static void 10554 f_sin(typval_T *argvars, typval_T *rettv) 10555 { 10556 float_T f = 0.0; 10557 10558 rettv->v_type = VAR_FLOAT; 10559 if (get_float_arg(argvars, &f) == OK) 10560 rettv->vval.v_float = sin(f); 10561 else 10562 rettv->vval.v_float = 0.0; 10563 } 10564 10565 /* 10566 * "sinh()" function 10567 */ 10568 static void 10569 f_sinh(typval_T *argvars, typval_T *rettv) 10570 { 10571 float_T f = 0.0; 10572 10573 rettv->v_type = VAR_FLOAT; 10574 if (get_float_arg(argvars, &f) == OK) 10575 rettv->vval.v_float = sinh(f); 10576 else 10577 rettv->vval.v_float = 0.0; 10578 } 10579 #endif 10580 10581 static int 10582 #ifdef __BORLANDC__ 10583 _RTLENTRYF 10584 #endif 10585 item_compare(const void *s1, const void *s2); 10586 static int 10587 #ifdef __BORLANDC__ 10588 _RTLENTRYF 10589 #endif 10590 item_compare2(const void *s1, const void *s2); 10591 10592 /* struct used in the array that's given to qsort() */ 10593 typedef struct 10594 { 10595 listitem_T *item; 10596 int idx; 10597 } sortItem_T; 10598 10599 /* struct storing information about current sort */ 10600 typedef struct 10601 { 10602 int item_compare_ic; 10603 int item_compare_numeric; 10604 int item_compare_numbers; 10605 #ifdef FEAT_FLOAT 10606 int item_compare_float; 10607 #endif 10608 char_u *item_compare_func; 10609 partial_T *item_compare_partial; 10610 dict_T *item_compare_selfdict; 10611 int item_compare_func_err; 10612 int item_compare_keep_zero; 10613 } sortinfo_T; 10614 static sortinfo_T *sortinfo = NULL; 10615 static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort); 10616 #define ITEM_COMPARE_FAIL 999 10617 10618 /* 10619 * Compare functions for f_sort() and f_uniq() below. 10620 */ 10621 static int 10622 #ifdef __BORLANDC__ 10623 _RTLENTRYF 10624 #endif 10625 item_compare(const void *s1, const void *s2) 10626 { 10627 sortItem_T *si1, *si2; 10628 typval_T *tv1, *tv2; 10629 char_u *p1, *p2; 10630 char_u *tofree1 = NULL, *tofree2 = NULL; 10631 int res; 10632 char_u numbuf1[NUMBUFLEN]; 10633 char_u numbuf2[NUMBUFLEN]; 10634 10635 si1 = (sortItem_T *)s1; 10636 si2 = (sortItem_T *)s2; 10637 tv1 = &si1->item->li_tv; 10638 tv2 = &si2->item->li_tv; 10639 10640 if (sortinfo->item_compare_numbers) 10641 { 10642 varnumber_T v1 = get_tv_number(tv1); 10643 varnumber_T v2 = get_tv_number(tv2); 10644 10645 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; 10646 } 10647 10648 #ifdef FEAT_FLOAT 10649 if (sortinfo->item_compare_float) 10650 { 10651 float_T v1 = get_tv_float(tv1); 10652 float_T v2 = get_tv_float(tv2); 10653 10654 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; 10655 } 10656 #endif 10657 10658 /* tv2string() puts quotes around a string and allocates memory. Don't do 10659 * that for string variables. Use a single quote when comparing with a 10660 * non-string to do what the docs promise. */ 10661 if (tv1->v_type == VAR_STRING) 10662 { 10663 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) 10664 p1 = (char_u *)"'"; 10665 else 10666 p1 = tv1->vval.v_string; 10667 } 10668 else 10669 p1 = tv2string(tv1, &tofree1, numbuf1, 0); 10670 if (tv2->v_type == VAR_STRING) 10671 { 10672 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) 10673 p2 = (char_u *)"'"; 10674 else 10675 p2 = tv2->vval.v_string; 10676 } 10677 else 10678 p2 = tv2string(tv2, &tofree2, numbuf2, 0); 10679 if (p1 == NULL) 10680 p1 = (char_u *)""; 10681 if (p2 == NULL) 10682 p2 = (char_u *)""; 10683 if (!sortinfo->item_compare_numeric) 10684 { 10685 if (sortinfo->item_compare_ic) 10686 res = STRICMP(p1, p2); 10687 else 10688 res = STRCMP(p1, p2); 10689 } 10690 else 10691 { 10692 double n1, n2; 10693 n1 = strtod((char *)p1, (char **)&p1); 10694 n2 = strtod((char *)p2, (char **)&p2); 10695 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1; 10696 } 10697 10698 /* When the result would be zero, compare the item indexes. Makes the 10699 * sort stable. */ 10700 if (res == 0 && !sortinfo->item_compare_keep_zero) 10701 res = si1->idx > si2->idx ? 1 : -1; 10702 10703 vim_free(tofree1); 10704 vim_free(tofree2); 10705 return res; 10706 } 10707 10708 static int 10709 #ifdef __BORLANDC__ 10710 _RTLENTRYF 10711 #endif 10712 item_compare2(const void *s1, const void *s2) 10713 { 10714 sortItem_T *si1, *si2; 10715 int res; 10716 typval_T rettv; 10717 typval_T argv[3]; 10718 int dummy; 10719 char_u *func_name; 10720 partial_T *partial = sortinfo->item_compare_partial; 10721 10722 /* shortcut after failure in previous call; compare all items equal */ 10723 if (sortinfo->item_compare_func_err) 10724 return 0; 10725 10726 si1 = (sortItem_T *)s1; 10727 si2 = (sortItem_T *)s2; 10728 10729 if (partial == NULL) 10730 func_name = sortinfo->item_compare_func; 10731 else 10732 func_name = partial_name(partial); 10733 10734 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED 10735 * in the copy without changing the original list items. */ 10736 copy_tv(&si1->item->li_tv, &argv[0]); 10737 copy_tv(&si2->item->li_tv, &argv[1]); 10738 10739 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */ 10740 res = call_func(func_name, (int)STRLEN(func_name), 10741 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, 10742 partial, sortinfo->item_compare_selfdict); 10743 clear_tv(&argv[0]); 10744 clear_tv(&argv[1]); 10745 10746 if (res == FAIL) 10747 res = ITEM_COMPARE_FAIL; 10748 else 10749 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err); 10750 if (sortinfo->item_compare_func_err) 10751 res = ITEM_COMPARE_FAIL; /* return value has wrong type */ 10752 clear_tv(&rettv); 10753 10754 /* When the result would be zero, compare the pointers themselves. Makes 10755 * the sort stable. */ 10756 if (res == 0 && !sortinfo->item_compare_keep_zero) 10757 res = si1->idx > si2->idx ? 1 : -1; 10758 10759 return res; 10760 } 10761 10762 /* 10763 * "sort({list})" function 10764 */ 10765 static void 10766 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) 10767 { 10768 list_T *l; 10769 listitem_T *li; 10770 sortItem_T *ptrs; 10771 sortinfo_T *old_sortinfo; 10772 sortinfo_T info; 10773 long len; 10774 long i; 10775 10776 /* Pointer to current info struct used in compare function. Save and 10777 * restore the current one for nested calls. */ 10778 old_sortinfo = sortinfo; 10779 sortinfo = &info; 10780 10781 if (argvars[0].v_type != VAR_LIST) 10782 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()"); 10783 else 10784 { 10785 l = argvars[0].vval.v_list; 10786 if (l == NULL || tv_check_lock(l->lv_lock, 10787 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")), 10788 TRUE)) 10789 goto theend; 10790 rettv_list_set(rettv, l); 10791 10792 len = list_len(l); 10793 if (len <= 1) 10794 goto theend; /* short list sorts pretty quickly */ 10795 10796 info.item_compare_ic = FALSE; 10797 info.item_compare_numeric = FALSE; 10798 info.item_compare_numbers = FALSE; 10799 #ifdef FEAT_FLOAT 10800 info.item_compare_float = FALSE; 10801 #endif 10802 info.item_compare_func = NULL; 10803 info.item_compare_partial = NULL; 10804 info.item_compare_selfdict = NULL; 10805 if (argvars[1].v_type != VAR_UNKNOWN) 10806 { 10807 /* optional second argument: {func} */ 10808 if (argvars[1].v_type == VAR_FUNC) 10809 info.item_compare_func = argvars[1].vval.v_string; 10810 else if (argvars[1].v_type == VAR_PARTIAL) 10811 info.item_compare_partial = argvars[1].vval.v_partial; 10812 else 10813 { 10814 int error = FALSE; 10815 10816 i = (long)get_tv_number_chk(&argvars[1], &error); 10817 if (error) 10818 goto theend; /* type error; errmsg already given */ 10819 if (i == 1) 10820 info.item_compare_ic = TRUE; 10821 else if (argvars[1].v_type != VAR_NUMBER) 10822 info.item_compare_func = get_tv_string(&argvars[1]); 10823 else if (i != 0) 10824 { 10825 EMSG(_(e_invarg)); 10826 goto theend; 10827 } 10828 if (info.item_compare_func != NULL) 10829 { 10830 if (*info.item_compare_func == NUL) 10831 { 10832 /* empty string means default sort */ 10833 info.item_compare_func = NULL; 10834 } 10835 else if (STRCMP(info.item_compare_func, "n") == 0) 10836 { 10837 info.item_compare_func = NULL; 10838 info.item_compare_numeric = TRUE; 10839 } 10840 else if (STRCMP(info.item_compare_func, "N") == 0) 10841 { 10842 info.item_compare_func = NULL; 10843 info.item_compare_numbers = TRUE; 10844 } 10845 #ifdef FEAT_FLOAT 10846 else if (STRCMP(info.item_compare_func, "f") == 0) 10847 { 10848 info.item_compare_func = NULL; 10849 info.item_compare_float = TRUE; 10850 } 10851 #endif 10852 else if (STRCMP(info.item_compare_func, "i") == 0) 10853 { 10854 info.item_compare_func = NULL; 10855 info.item_compare_ic = TRUE; 10856 } 10857 } 10858 } 10859 10860 if (argvars[2].v_type != VAR_UNKNOWN) 10861 { 10862 /* optional third argument: {dict} */ 10863 if (argvars[2].v_type != VAR_DICT) 10864 { 10865 EMSG(_(e_dictreq)); 10866 goto theend; 10867 } 10868 info.item_compare_selfdict = argvars[2].vval.v_dict; 10869 } 10870 } 10871 10872 /* Make an array with each entry pointing to an item in the List. */ 10873 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T))); 10874 if (ptrs == NULL) 10875 goto theend; 10876 10877 i = 0; 10878 if (sort) 10879 { 10880 /* sort(): ptrs will be the list to sort */ 10881 for (li = l->lv_first; li != NULL; li = li->li_next) 10882 { 10883 ptrs[i].item = li; 10884 ptrs[i].idx = i; 10885 ++i; 10886 } 10887 10888 info.item_compare_func_err = FALSE; 10889 info.item_compare_keep_zero = FALSE; 10890 /* test the compare function */ 10891 if ((info.item_compare_func != NULL 10892 || info.item_compare_partial != NULL) 10893 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1]) 10894 == ITEM_COMPARE_FAIL) 10895 EMSG(_("E702: Sort compare function failed")); 10896 else 10897 { 10898 /* Sort the array with item pointers. */ 10899 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T), 10900 info.item_compare_func == NULL 10901 && info.item_compare_partial == NULL 10902 ? item_compare : item_compare2); 10903 10904 if (!info.item_compare_func_err) 10905 { 10906 /* Clear the List and append the items in sorted order. */ 10907 l->lv_first = l->lv_last = l->lv_idx_item = NULL; 10908 l->lv_len = 0; 10909 for (i = 0; i < len; ++i) 10910 list_append(l, ptrs[i].item); 10911 } 10912 } 10913 } 10914 else 10915 { 10916 int (*item_compare_func_ptr)(const void *, const void *); 10917 10918 /* f_uniq(): ptrs will be a stack of items to remove */ 10919 info.item_compare_func_err = FALSE; 10920 info.item_compare_keep_zero = TRUE; 10921 item_compare_func_ptr = info.item_compare_func != NULL 10922 || info.item_compare_partial != NULL 10923 ? item_compare2 : item_compare; 10924 10925 for (li = l->lv_first; li != NULL && li->li_next != NULL; 10926 li = li->li_next) 10927 { 10928 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next) 10929 == 0) 10930 ptrs[i++].item = li; 10931 if (info.item_compare_func_err) 10932 { 10933 EMSG(_("E882: Uniq compare function failed")); 10934 break; 10935 } 10936 } 10937 10938 if (!info.item_compare_func_err) 10939 { 10940 while (--i >= 0) 10941 { 10942 li = ptrs[i].item->li_next; 10943 ptrs[i].item->li_next = li->li_next; 10944 if (li->li_next != NULL) 10945 li->li_next->li_prev = ptrs[i].item; 10946 else 10947 l->lv_last = ptrs[i].item; 10948 list_fix_watch(l, li); 10949 listitem_free(li); 10950 l->lv_len--; 10951 } 10952 } 10953 } 10954 10955 vim_free(ptrs); 10956 } 10957 theend: 10958 sortinfo = old_sortinfo; 10959 } 10960 10961 /* 10962 * "sort({list})" function 10963 */ 10964 static void 10965 f_sort(typval_T *argvars, typval_T *rettv) 10966 { 10967 do_sort_uniq(argvars, rettv, TRUE); 10968 } 10969 10970 /* 10971 * "uniq({list})" function 10972 */ 10973 static void 10974 f_uniq(typval_T *argvars, typval_T *rettv) 10975 { 10976 do_sort_uniq(argvars, rettv, FALSE); 10977 } 10978 10979 /* 10980 * "soundfold({word})" function 10981 */ 10982 static void 10983 f_soundfold(typval_T *argvars, typval_T *rettv) 10984 { 10985 char_u *s; 10986 10987 rettv->v_type = VAR_STRING; 10988 s = get_tv_string(&argvars[0]); 10989 #ifdef FEAT_SPELL 10990 rettv->vval.v_string = eval_soundfold(s); 10991 #else 10992 rettv->vval.v_string = vim_strsave(s); 10993 #endif 10994 } 10995 10996 /* 10997 * "spellbadword()" function 10998 */ 10999 static void 11000 f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv) 11001 { 11002 char_u *word = (char_u *)""; 11003 hlf_T attr = HLF_COUNT; 11004 int len = 0; 11005 11006 if (rettv_list_alloc(rettv) == FAIL) 11007 return; 11008 11009 #ifdef FEAT_SPELL 11010 if (argvars[0].v_type == VAR_UNKNOWN) 11011 { 11012 /* Find the start and length of the badly spelled word. */ 11013 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr); 11014 if (len != 0) 11015 word = ml_get_cursor(); 11016 } 11017 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL) 11018 { 11019 char_u *str = get_tv_string_chk(&argvars[0]); 11020 int capcol = -1; 11021 11022 if (str != NULL) 11023 { 11024 /* Check the argument for spelling. */ 11025 while (*str != NUL) 11026 { 11027 len = spell_check(curwin, str, &attr, &capcol, FALSE); 11028 if (attr != HLF_COUNT) 11029 { 11030 word = str; 11031 break; 11032 } 11033 str += len; 11034 } 11035 } 11036 } 11037 #endif 11038 11039 list_append_string(rettv->vval.v_list, word, len); 11040 list_append_string(rettv->vval.v_list, (char_u *)( 11041 attr == HLF_SPB ? "bad" : 11042 attr == HLF_SPR ? "rare" : 11043 attr == HLF_SPL ? "local" : 11044 attr == HLF_SPC ? "caps" : 11045 ""), -1); 11046 } 11047 11048 /* 11049 * "spellsuggest()" function 11050 */ 11051 static void 11052 f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv) 11053 { 11054 #ifdef FEAT_SPELL 11055 char_u *str; 11056 int typeerr = FALSE; 11057 int maxcount; 11058 garray_T ga; 11059 int i; 11060 listitem_T *li; 11061 int need_capital = FALSE; 11062 #endif 11063 11064 if (rettv_list_alloc(rettv) == FAIL) 11065 return; 11066 11067 #ifdef FEAT_SPELL 11068 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) 11069 { 11070 str = get_tv_string(&argvars[0]); 11071 if (argvars[1].v_type != VAR_UNKNOWN) 11072 { 11073 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr); 11074 if (maxcount <= 0) 11075 return; 11076 if (argvars[2].v_type != VAR_UNKNOWN) 11077 { 11078 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr); 11079 if (typeerr) 11080 return; 11081 } 11082 } 11083 else 11084 maxcount = 25; 11085 11086 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE); 11087 11088 for (i = 0; i < ga.ga_len; ++i) 11089 { 11090 str = ((char_u **)ga.ga_data)[i]; 11091 11092 li = listitem_alloc(); 11093 if (li == NULL) 11094 vim_free(str); 11095 else 11096 { 11097 li->li_tv.v_type = VAR_STRING; 11098 li->li_tv.v_lock = 0; 11099 li->li_tv.vval.v_string = str; 11100 list_append(rettv->vval.v_list, li); 11101 } 11102 } 11103 ga_clear(&ga); 11104 } 11105 #endif 11106 } 11107 11108 static void 11109 f_split(typval_T *argvars, typval_T *rettv) 11110 { 11111 char_u *str; 11112 char_u *end; 11113 char_u *pat = NULL; 11114 regmatch_T regmatch; 11115 char_u patbuf[NUMBUFLEN]; 11116 char_u *save_cpo; 11117 int match; 11118 colnr_T col = 0; 11119 int keepempty = FALSE; 11120 int typeerr = FALSE; 11121 11122 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ 11123 save_cpo = p_cpo; 11124 p_cpo = (char_u *)""; 11125 11126 str = get_tv_string(&argvars[0]); 11127 if (argvars[1].v_type != VAR_UNKNOWN) 11128 { 11129 pat = get_tv_string_buf_chk(&argvars[1], patbuf); 11130 if (pat == NULL) 11131 typeerr = TRUE; 11132 if (argvars[2].v_type != VAR_UNKNOWN) 11133 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr); 11134 } 11135 if (pat == NULL || *pat == NUL) 11136 pat = (char_u *)"[\\x01- ]\\+"; 11137 11138 if (rettv_list_alloc(rettv) == FAIL) 11139 return; 11140 if (typeerr) 11141 return; 11142 11143 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); 11144 if (regmatch.regprog != NULL) 11145 { 11146 regmatch.rm_ic = FALSE; 11147 while (*str != NUL || keepempty) 11148 { 11149 if (*str == NUL) 11150 match = FALSE; /* empty item at the end */ 11151 else 11152 match = vim_regexec_nl(®match, str, col); 11153 if (match) 11154 end = regmatch.startp[0]; 11155 else 11156 end = str + STRLEN(str); 11157 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0 11158 && *str != NUL && match && end < regmatch.endp[0])) 11159 { 11160 if (list_append_string(rettv->vval.v_list, str, 11161 (int)(end - str)) == FAIL) 11162 break; 11163 } 11164 if (!match) 11165 break; 11166 /* Advance to just after the match. */ 11167 if (regmatch.endp[0] > str) 11168 col = 0; 11169 else 11170 { 11171 /* Don't get stuck at the same match. */ 11172 #ifdef FEAT_MBYTE 11173 col = (*mb_ptr2len)(regmatch.endp[0]); 11174 #else 11175 col = 1; 11176 #endif 11177 } 11178 str = regmatch.endp[0]; 11179 } 11180 11181 vim_regfree(regmatch.regprog); 11182 } 11183 11184 p_cpo = save_cpo; 11185 } 11186 11187 #ifdef FEAT_FLOAT 11188 /* 11189 * "sqrt()" function 11190 */ 11191 static void 11192 f_sqrt(typval_T *argvars, typval_T *rettv) 11193 { 11194 float_T f = 0.0; 11195 11196 rettv->v_type = VAR_FLOAT; 11197 if (get_float_arg(argvars, &f) == OK) 11198 rettv->vval.v_float = sqrt(f); 11199 else 11200 rettv->vval.v_float = 0.0; 11201 } 11202 11203 /* 11204 * "str2float()" function 11205 */ 11206 static void 11207 f_str2float(typval_T *argvars, typval_T *rettv) 11208 { 11209 char_u *p = skipwhite(get_tv_string(&argvars[0])); 11210 int isneg = (*p == '-'); 11211 11212 if (*p == '+' || *p == '-') 11213 p = skipwhite(p + 1); 11214 (void)string2float(p, &rettv->vval.v_float); 11215 if (isneg) 11216 rettv->vval.v_float *= -1; 11217 rettv->v_type = VAR_FLOAT; 11218 } 11219 #endif 11220 11221 /* 11222 * "str2nr()" function 11223 */ 11224 static void 11225 f_str2nr(typval_T *argvars, typval_T *rettv) 11226 { 11227 int base = 10; 11228 char_u *p; 11229 varnumber_T n; 11230 int what; 11231 int isneg; 11232 11233 if (argvars[1].v_type != VAR_UNKNOWN) 11234 { 11235 base = (int)get_tv_number(&argvars[1]); 11236 if (base != 2 && base != 8 && base != 10 && base != 16) 11237 { 11238 EMSG(_(e_invarg)); 11239 return; 11240 } 11241 } 11242 11243 p = skipwhite(get_tv_string(&argvars[0])); 11244 isneg = (*p == '-'); 11245 if (*p == '+' || *p == '-') 11246 p = skipwhite(p + 1); 11247 switch (base) 11248 { 11249 case 2: what = STR2NR_BIN + STR2NR_FORCE; break; 11250 case 8: what = STR2NR_OCT + STR2NR_FORCE; break; 11251 case 16: what = STR2NR_HEX + STR2NR_FORCE; break; 11252 default: what = 0; 11253 } 11254 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0); 11255 if (isneg) 11256 rettv->vval.v_number = -n; 11257 else 11258 rettv->vval.v_number = n; 11259 11260 } 11261 11262 #ifdef HAVE_STRFTIME 11263 /* 11264 * "strftime({format}[, {time}])" function 11265 */ 11266 static void 11267 f_strftime(typval_T *argvars, typval_T *rettv) 11268 { 11269 char_u result_buf[256]; 11270 struct tm *curtime; 11271 time_t seconds; 11272 char_u *p; 11273 11274 rettv->v_type = VAR_STRING; 11275 11276 p = get_tv_string(&argvars[0]); 11277 if (argvars[1].v_type == VAR_UNKNOWN) 11278 seconds = time(NULL); 11279 else 11280 seconds = (time_t)get_tv_number(&argvars[1]); 11281 curtime = localtime(&seconds); 11282 /* MSVC returns NULL for an invalid value of seconds. */ 11283 if (curtime == NULL) 11284 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)")); 11285 else 11286 { 11287 # ifdef FEAT_MBYTE 11288 vimconv_T conv; 11289 char_u *enc; 11290 11291 conv.vc_type = CONV_NONE; 11292 enc = enc_locale(); 11293 convert_setup(&conv, p_enc, enc); 11294 if (conv.vc_type != CONV_NONE) 11295 p = string_convert(&conv, p, NULL); 11296 # endif 11297 if (p != NULL) 11298 (void)strftime((char *)result_buf, sizeof(result_buf), 11299 (char *)p, curtime); 11300 else 11301 result_buf[0] = NUL; 11302 11303 # ifdef FEAT_MBYTE 11304 if (conv.vc_type != CONV_NONE) 11305 vim_free(p); 11306 convert_setup(&conv, enc, p_enc); 11307 if (conv.vc_type != CONV_NONE) 11308 rettv->vval.v_string = string_convert(&conv, result_buf, NULL); 11309 else 11310 # endif 11311 rettv->vval.v_string = vim_strsave(result_buf); 11312 11313 # ifdef FEAT_MBYTE 11314 /* Release conversion descriptors */ 11315 convert_setup(&conv, NULL, NULL); 11316 vim_free(enc); 11317 # endif 11318 } 11319 } 11320 #endif 11321 11322 /* 11323 * "strgetchar()" function 11324 */ 11325 static void 11326 f_strgetchar(typval_T *argvars, typval_T *rettv) 11327 { 11328 char_u *str; 11329 int len; 11330 int error = FALSE; 11331 int charidx; 11332 11333 rettv->vval.v_number = -1; 11334 str = get_tv_string_chk(&argvars[0]); 11335 if (str == NULL) 11336 return; 11337 len = (int)STRLEN(str); 11338 charidx = (int)get_tv_number_chk(&argvars[1], &error); 11339 if (error) 11340 return; 11341 #ifdef FEAT_MBYTE 11342 { 11343 int byteidx = 0; 11344 11345 while (charidx >= 0 && byteidx < len) 11346 { 11347 if (charidx == 0) 11348 { 11349 rettv->vval.v_number = mb_ptr2char(str + byteidx); 11350 break; 11351 } 11352 --charidx; 11353 byteidx += MB_CPTR2LEN(str + byteidx); 11354 } 11355 } 11356 #else 11357 if (charidx < len) 11358 rettv->vval.v_number = str[charidx]; 11359 #endif 11360 } 11361 11362 /* 11363 * "stridx()" function 11364 */ 11365 static void 11366 f_stridx(typval_T *argvars, typval_T *rettv) 11367 { 11368 char_u buf[NUMBUFLEN]; 11369 char_u *needle; 11370 char_u *haystack; 11371 char_u *save_haystack; 11372 char_u *pos; 11373 int start_idx; 11374 11375 needle = get_tv_string_chk(&argvars[1]); 11376 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf); 11377 rettv->vval.v_number = -1; 11378 if (needle == NULL || haystack == NULL) 11379 return; /* type error; errmsg already given */ 11380 11381 if (argvars[2].v_type != VAR_UNKNOWN) 11382 { 11383 int error = FALSE; 11384 11385 start_idx = (int)get_tv_number_chk(&argvars[2], &error); 11386 if (error || start_idx >= (int)STRLEN(haystack)) 11387 return; 11388 if (start_idx >= 0) 11389 haystack += start_idx; 11390 } 11391 11392 pos = (char_u *)strstr((char *)haystack, (char *)needle); 11393 if (pos != NULL) 11394 rettv->vval.v_number = (varnumber_T)(pos - save_haystack); 11395 } 11396 11397 /* 11398 * "string()" function 11399 */ 11400 static void 11401 f_string(typval_T *argvars, typval_T *rettv) 11402 { 11403 char_u *tofree; 11404 char_u numbuf[NUMBUFLEN]; 11405 11406 rettv->v_type = VAR_STRING; 11407 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf, 11408 get_copyID()); 11409 /* Make a copy if we have a value but it's not in allocated memory. */ 11410 if (rettv->vval.v_string != NULL && tofree == NULL) 11411 rettv->vval.v_string = vim_strsave(rettv->vval.v_string); 11412 } 11413 11414 /* 11415 * "strlen()" function 11416 */ 11417 static void 11418 f_strlen(typval_T *argvars, typval_T *rettv) 11419 { 11420 rettv->vval.v_number = (varnumber_T)(STRLEN( 11421 get_tv_string(&argvars[0]))); 11422 } 11423 11424 /* 11425 * "strchars()" function 11426 */ 11427 static void 11428 f_strchars(typval_T *argvars, typval_T *rettv) 11429 { 11430 char_u *s = get_tv_string(&argvars[0]); 11431 int skipcc = 0; 11432 #ifdef FEAT_MBYTE 11433 varnumber_T len = 0; 11434 int (*func_mb_ptr2char_adv)(char_u **pp); 11435 #endif 11436 11437 if (argvars[1].v_type != VAR_UNKNOWN) 11438 skipcc = (int)get_tv_number_chk(&argvars[1], NULL); 11439 if (skipcc < 0 || skipcc > 1) 11440 EMSG(_(e_invarg)); 11441 else 11442 { 11443 #ifdef FEAT_MBYTE 11444 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv; 11445 while (*s != NUL) 11446 { 11447 func_mb_ptr2char_adv(&s); 11448 ++len; 11449 } 11450 rettv->vval.v_number = len; 11451 #else 11452 rettv->vval.v_number = (varnumber_T)(STRLEN(s)); 11453 #endif 11454 } 11455 } 11456 11457 /* 11458 * "strdisplaywidth()" function 11459 */ 11460 static void 11461 f_strdisplaywidth(typval_T *argvars, typval_T *rettv) 11462 { 11463 char_u *s = get_tv_string(&argvars[0]); 11464 int col = 0; 11465 11466 if (argvars[1].v_type != VAR_UNKNOWN) 11467 col = (int)get_tv_number(&argvars[1]); 11468 11469 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col); 11470 } 11471 11472 /* 11473 * "strwidth()" function 11474 */ 11475 static void 11476 f_strwidth(typval_T *argvars, typval_T *rettv) 11477 { 11478 char_u *s = get_tv_string(&argvars[0]); 11479 11480 rettv->vval.v_number = (varnumber_T)( 11481 #ifdef FEAT_MBYTE 11482 mb_string2cells(s, -1) 11483 #else 11484 STRLEN(s) 11485 #endif 11486 ); 11487 } 11488 11489 /* 11490 * "strcharpart()" function 11491 */ 11492 static void 11493 f_strcharpart(typval_T *argvars, typval_T *rettv) 11494 { 11495 #ifdef FEAT_MBYTE 11496 char_u *p; 11497 int nchar; 11498 int nbyte = 0; 11499 int charlen; 11500 int len = 0; 11501 int slen; 11502 int error = FALSE; 11503 11504 p = get_tv_string(&argvars[0]); 11505 slen = (int)STRLEN(p); 11506 11507 nchar = (int)get_tv_number_chk(&argvars[1], &error); 11508 if (!error) 11509 { 11510 if (nchar > 0) 11511 while (nchar > 0 && nbyte < slen) 11512 { 11513 nbyte += MB_CPTR2LEN(p + nbyte); 11514 --nchar; 11515 } 11516 else 11517 nbyte = nchar; 11518 if (argvars[2].v_type != VAR_UNKNOWN) 11519 { 11520 charlen = (int)get_tv_number(&argvars[2]); 11521 while (charlen > 0 && nbyte + len < slen) 11522 { 11523 int off = nbyte + len; 11524 11525 if (off < 0) 11526 len += 1; 11527 else 11528 len += MB_CPTR2LEN(p + off); 11529 --charlen; 11530 } 11531 } 11532 else 11533 len = slen - nbyte; /* default: all bytes that are available. */ 11534 } 11535 11536 /* 11537 * Only return the overlap between the specified part and the actual 11538 * string. 11539 */ 11540 if (nbyte < 0) 11541 { 11542 len += nbyte; 11543 nbyte = 0; 11544 } 11545 else if (nbyte > slen) 11546 nbyte = slen; 11547 if (len < 0) 11548 len = 0; 11549 else if (nbyte + len > slen) 11550 len = slen - nbyte; 11551 11552 rettv->v_type = VAR_STRING; 11553 rettv->vval.v_string = vim_strnsave(p + nbyte, len); 11554 #else 11555 f_strpart(argvars, rettv); 11556 #endif 11557 } 11558 11559 /* 11560 * "strpart()" function 11561 */ 11562 static void 11563 f_strpart(typval_T *argvars, typval_T *rettv) 11564 { 11565 char_u *p; 11566 int n; 11567 int len; 11568 int slen; 11569 int error = FALSE; 11570 11571 p = get_tv_string(&argvars[0]); 11572 slen = (int)STRLEN(p); 11573 11574 n = (int)get_tv_number_chk(&argvars[1], &error); 11575 if (error) 11576 len = 0; 11577 else if (argvars[2].v_type != VAR_UNKNOWN) 11578 len = (int)get_tv_number(&argvars[2]); 11579 else 11580 len = slen - n; /* default len: all bytes that are available. */ 11581 11582 /* 11583 * Only return the overlap between the specified part and the actual 11584 * string. 11585 */ 11586 if (n < 0) 11587 { 11588 len += n; 11589 n = 0; 11590 } 11591 else if (n > slen) 11592 n = slen; 11593 if (len < 0) 11594 len = 0; 11595 else if (n + len > slen) 11596 len = slen - n; 11597 11598 rettv->v_type = VAR_STRING; 11599 rettv->vval.v_string = vim_strnsave(p + n, len); 11600 } 11601 11602 /* 11603 * "strridx()" function 11604 */ 11605 static void 11606 f_strridx(typval_T *argvars, typval_T *rettv) 11607 { 11608 char_u buf[NUMBUFLEN]; 11609 char_u *needle; 11610 char_u *haystack; 11611 char_u *rest; 11612 char_u *lastmatch = NULL; 11613 int haystack_len, end_idx; 11614 11615 needle = get_tv_string_chk(&argvars[1]); 11616 haystack = get_tv_string_buf_chk(&argvars[0], buf); 11617 11618 rettv->vval.v_number = -1; 11619 if (needle == NULL || haystack == NULL) 11620 return; /* type error; errmsg already given */ 11621 11622 haystack_len = (int)STRLEN(haystack); 11623 if (argvars[2].v_type != VAR_UNKNOWN) 11624 { 11625 /* Third argument: upper limit for index */ 11626 end_idx = (int)get_tv_number_chk(&argvars[2], NULL); 11627 if (end_idx < 0) 11628 return; /* can never find a match */ 11629 } 11630 else 11631 end_idx = haystack_len; 11632 11633 if (*needle == NUL) 11634 { 11635 /* Empty string matches past the end. */ 11636 lastmatch = haystack + end_idx; 11637 } 11638 else 11639 { 11640 for (rest = haystack; *rest != '\0'; ++rest) 11641 { 11642 rest = (char_u *)strstr((char *)rest, (char *)needle); 11643 if (rest == NULL || rest > haystack + end_idx) 11644 break; 11645 lastmatch = rest; 11646 } 11647 } 11648 11649 if (lastmatch == NULL) 11650 rettv->vval.v_number = -1; 11651 else 11652 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack); 11653 } 11654 11655 /* 11656 * "strtrans()" function 11657 */ 11658 static void 11659 f_strtrans(typval_T *argvars, typval_T *rettv) 11660 { 11661 rettv->v_type = VAR_STRING; 11662 rettv->vval.v_string = transstr(get_tv_string(&argvars[0])); 11663 } 11664 11665 /* 11666 * "submatch()" function 11667 */ 11668 static void 11669 f_submatch(typval_T *argvars, typval_T *rettv) 11670 { 11671 int error = FALSE; 11672 int no; 11673 int retList = 0; 11674 11675 no = (int)get_tv_number_chk(&argvars[0], &error); 11676 if (error) 11677 return; 11678 if (no < 0 || no >= NSUBEXP) 11679 { 11680 EMSGN(_("E935: invalid submatch number: %d"), no); 11681 return; 11682 } 11683 if (argvars[1].v_type != VAR_UNKNOWN) 11684 retList = (int)get_tv_number_chk(&argvars[1], &error); 11685 if (error) 11686 return; 11687 11688 if (retList == 0) 11689 { 11690 rettv->v_type = VAR_STRING; 11691 rettv->vval.v_string = reg_submatch(no); 11692 } 11693 else 11694 { 11695 rettv->v_type = VAR_LIST; 11696 rettv->vval.v_list = reg_submatch_list(no); 11697 } 11698 } 11699 11700 /* 11701 * "substitute()" function 11702 */ 11703 static void 11704 f_substitute(typval_T *argvars, typval_T *rettv) 11705 { 11706 char_u patbuf[NUMBUFLEN]; 11707 char_u subbuf[NUMBUFLEN]; 11708 char_u flagsbuf[NUMBUFLEN]; 11709 11710 char_u *str = get_tv_string_chk(&argvars[0]); 11711 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf); 11712 char_u *sub = NULL; 11713 typval_T *expr = NULL; 11714 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf); 11715 11716 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL) 11717 expr = &argvars[2]; 11718 else 11719 sub = get_tv_string_buf_chk(&argvars[2], subbuf); 11720 11721 rettv->v_type = VAR_STRING; 11722 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL) 11723 || flg == NULL) 11724 rettv->vval.v_string = NULL; 11725 else 11726 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg); 11727 } 11728 11729 /* 11730 * "synID(lnum, col, trans)" function 11731 */ 11732 static void 11733 f_synID(typval_T *argvars UNUSED, typval_T *rettv) 11734 { 11735 int id = 0; 11736 #ifdef FEAT_SYN_HL 11737 linenr_T lnum; 11738 colnr_T col; 11739 int trans; 11740 int transerr = FALSE; 11741 11742 lnum = get_tv_lnum(argvars); /* -1 on type error */ 11743 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */ 11744 trans = (int)get_tv_number_chk(&argvars[2], &transerr); 11745 11746 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count 11747 && col >= 0 && col < (long)STRLEN(ml_get(lnum))) 11748 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE); 11749 #endif 11750 11751 rettv->vval.v_number = id; 11752 } 11753 11754 /* 11755 * "synIDattr(id, what [, mode])" function 11756 */ 11757 static void 11758 f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv) 11759 { 11760 char_u *p = NULL; 11761 #ifdef FEAT_SYN_HL 11762 int id; 11763 char_u *what; 11764 char_u *mode; 11765 char_u modebuf[NUMBUFLEN]; 11766 int modec; 11767 11768 id = (int)get_tv_number(&argvars[0]); 11769 what = get_tv_string(&argvars[1]); 11770 if (argvars[2].v_type != VAR_UNKNOWN) 11771 { 11772 mode = get_tv_string_buf(&argvars[2], modebuf); 11773 modec = TOLOWER_ASC(mode[0]); 11774 if (modec != 't' && modec != 'c' && modec != 'g') 11775 modec = 0; /* replace invalid with current */ 11776 } 11777 else 11778 { 11779 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 11780 if (USE_24BIT) 11781 modec = 'g'; 11782 else 11783 #endif 11784 if (t_colors > 1) 11785 modec = 'c'; 11786 else 11787 modec = 't'; 11788 } 11789 11790 11791 switch (TOLOWER_ASC(what[0])) 11792 { 11793 case 'b': 11794 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */ 11795 p = highlight_color(id, what, modec); 11796 else /* bold */ 11797 p = highlight_has_attr(id, HL_BOLD, modec); 11798 break; 11799 11800 case 'f': /* fg[#] or font */ 11801 p = highlight_color(id, what, modec); 11802 break; 11803 11804 case 'i': 11805 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */ 11806 p = highlight_has_attr(id, HL_INVERSE, modec); 11807 else /* italic */ 11808 p = highlight_has_attr(id, HL_ITALIC, modec); 11809 break; 11810 11811 case 'n': /* name */ 11812 p = get_highlight_name_ext(NULL, id - 1, FALSE); 11813 break; 11814 11815 case 'r': /* reverse */ 11816 p = highlight_has_attr(id, HL_INVERSE, modec); 11817 break; 11818 11819 case 's': 11820 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */ 11821 p = highlight_color(id, what, modec); 11822 else /* standout */ 11823 p = highlight_has_attr(id, HL_STANDOUT, modec); 11824 break; 11825 11826 case 'u': 11827 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c') 11828 /* underline */ 11829 p = highlight_has_attr(id, HL_UNDERLINE, modec); 11830 else 11831 /* undercurl */ 11832 p = highlight_has_attr(id, HL_UNDERCURL, modec); 11833 break; 11834 } 11835 11836 if (p != NULL) 11837 p = vim_strsave(p); 11838 #endif 11839 rettv->v_type = VAR_STRING; 11840 rettv->vval.v_string = p; 11841 } 11842 11843 /* 11844 * "synIDtrans(id)" function 11845 */ 11846 static void 11847 f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv) 11848 { 11849 int id; 11850 11851 #ifdef FEAT_SYN_HL 11852 id = (int)get_tv_number(&argvars[0]); 11853 11854 if (id > 0) 11855 id = syn_get_final_id(id); 11856 else 11857 #endif 11858 id = 0; 11859 11860 rettv->vval.v_number = id; 11861 } 11862 11863 /* 11864 * "synconcealed(lnum, col)" function 11865 */ 11866 static void 11867 f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv) 11868 { 11869 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) 11870 linenr_T lnum; 11871 colnr_T col; 11872 int syntax_flags = 0; 11873 int cchar; 11874 int matchid = 0; 11875 char_u str[NUMBUFLEN]; 11876 #endif 11877 11878 rettv_list_set(rettv, NULL); 11879 11880 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) 11881 lnum = get_tv_lnum(argvars); /* -1 on type error */ 11882 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */ 11883 11884 vim_memset(str, NUL, sizeof(str)); 11885 11886 if (rettv_list_alloc(rettv) != FAIL) 11887 { 11888 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count 11889 && col >= 0 && col <= (long)STRLEN(ml_get(lnum)) 11890 && curwin->w_p_cole > 0) 11891 { 11892 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE); 11893 syntax_flags = get_syntax_info(&matchid); 11894 11895 /* get the conceal character */ 11896 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3) 11897 { 11898 cchar = syn_get_sub_char(); 11899 if (cchar == NUL && curwin->w_p_cole == 1) 11900 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal; 11901 if (cchar != NUL) 11902 { 11903 # ifdef FEAT_MBYTE 11904 if (has_mbyte) 11905 (*mb_char2bytes)(cchar, str); 11906 else 11907 # endif 11908 str[0] = cchar; 11909 } 11910 } 11911 } 11912 11913 list_append_number(rettv->vval.v_list, 11914 (syntax_flags & HL_CONCEAL) != 0); 11915 /* -1 to auto-determine strlen */ 11916 list_append_string(rettv->vval.v_list, str, -1); 11917 list_append_number(rettv->vval.v_list, matchid); 11918 } 11919 #endif 11920 } 11921 11922 /* 11923 * "synstack(lnum, col)" function 11924 */ 11925 static void 11926 f_synstack(typval_T *argvars UNUSED, typval_T *rettv) 11927 { 11928 #ifdef FEAT_SYN_HL 11929 linenr_T lnum; 11930 colnr_T col; 11931 int i; 11932 int id; 11933 #endif 11934 11935 rettv_list_set(rettv, NULL); 11936 11937 #ifdef FEAT_SYN_HL 11938 lnum = get_tv_lnum(argvars); /* -1 on type error */ 11939 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */ 11940 11941 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count 11942 && col >= 0 && col <= (long)STRLEN(ml_get(lnum)) 11943 && rettv_list_alloc(rettv) != FAIL) 11944 { 11945 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE); 11946 for (i = 0; ; ++i) 11947 { 11948 id = syn_get_stack_item(i); 11949 if (id < 0) 11950 break; 11951 if (list_append_number(rettv->vval.v_list, id) == FAIL) 11952 break; 11953 } 11954 } 11955 #endif 11956 } 11957 11958 static void 11959 get_cmd_output_as_rettv( 11960 typval_T *argvars, 11961 typval_T *rettv, 11962 int retlist) 11963 { 11964 char_u *res = NULL; 11965 char_u *p; 11966 char_u *infile = NULL; 11967 int err = FALSE; 11968 FILE *fd; 11969 list_T *list = NULL; 11970 int flags = SHELL_SILENT; 11971 11972 rettv->v_type = VAR_STRING; 11973 rettv->vval.v_string = NULL; 11974 if (check_restricted() || check_secure()) 11975 goto errret; 11976 11977 if (argvars[1].v_type != VAR_UNKNOWN) 11978 { 11979 /* 11980 * Write the text to a temp file, to be used for input of the shell 11981 * command. 11982 */ 11983 if ((infile = vim_tempname('i', TRUE)) == NULL) 11984 { 11985 EMSG(_(e_notmp)); 11986 goto errret; 11987 } 11988 11989 fd = mch_fopen((char *)infile, WRITEBIN); 11990 if (fd == NULL) 11991 { 11992 EMSG2(_(e_notopen), infile); 11993 goto errret; 11994 } 11995 if (argvars[1].v_type == VAR_NUMBER) 11996 { 11997 linenr_T lnum; 11998 buf_T *buf; 11999 12000 buf = buflist_findnr(argvars[1].vval.v_number); 12001 if (buf == NULL) 12002 { 12003 EMSGN(_(e_nobufnr), argvars[1].vval.v_number); 12004 fclose(fd); 12005 goto errret; 12006 } 12007 12008 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) 12009 { 12010 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p) 12011 if (putc(*p == '\n' ? NUL : *p, fd) == EOF) 12012 { 12013 err = TRUE; 12014 break; 12015 } 12016 if (putc(NL, fd) == EOF) 12017 { 12018 err = TRUE; 12019 break; 12020 } 12021 } 12022 } 12023 else if (argvars[1].v_type == VAR_LIST) 12024 { 12025 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL) 12026 err = TRUE; 12027 } 12028 else 12029 { 12030 size_t len; 12031 char_u buf[NUMBUFLEN]; 12032 12033 p = get_tv_string_buf_chk(&argvars[1], buf); 12034 if (p == NULL) 12035 { 12036 fclose(fd); 12037 goto errret; /* type error; errmsg already given */ 12038 } 12039 len = STRLEN(p); 12040 if (len > 0 && fwrite(p, len, 1, fd) != 1) 12041 err = TRUE; 12042 } 12043 if (fclose(fd) != 0) 12044 err = TRUE; 12045 if (err) 12046 { 12047 EMSG(_("E677: Error writing temp file")); 12048 goto errret; 12049 } 12050 } 12051 12052 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell 12053 * echoes typeahead, that messes up the display. */ 12054 if (!msg_silent) 12055 flags += SHELL_COOKED; 12056 12057 if (retlist) 12058 { 12059 int len; 12060 listitem_T *li; 12061 char_u *s = NULL; 12062 char_u *start; 12063 char_u *end; 12064 int i; 12065 12066 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len); 12067 if (res == NULL) 12068 goto errret; 12069 12070 list = list_alloc(); 12071 if (list == NULL) 12072 goto errret; 12073 12074 for (i = 0; i < len; ++i) 12075 { 12076 start = res + i; 12077 while (i < len && res[i] != NL) 12078 ++i; 12079 end = res + i; 12080 12081 s = alloc((unsigned)(end - start + 1)); 12082 if (s == NULL) 12083 goto errret; 12084 12085 for (p = s; start < end; ++p, ++start) 12086 *p = *start == NUL ? NL : *start; 12087 *p = NUL; 12088 12089 li = listitem_alloc(); 12090 if (li == NULL) 12091 { 12092 vim_free(s); 12093 goto errret; 12094 } 12095 li->li_tv.v_type = VAR_STRING; 12096 li->li_tv.v_lock = 0; 12097 li->li_tv.vval.v_string = s; 12098 list_append(list, li); 12099 } 12100 12101 rettv_list_set(rettv, list); 12102 list = NULL; 12103 } 12104 else 12105 { 12106 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL); 12107 #ifdef USE_CR 12108 /* translate <CR> into <NL> */ 12109 if (res != NULL) 12110 { 12111 char_u *s; 12112 12113 for (s = res; *s; ++s) 12114 { 12115 if (*s == CAR) 12116 *s = NL; 12117 } 12118 } 12119 #else 12120 # ifdef USE_CRNL 12121 /* translate <CR><NL> into <NL> */ 12122 if (res != NULL) 12123 { 12124 char_u *s, *d; 12125 12126 d = res; 12127 for (s = res; *s; ++s) 12128 { 12129 if (s[0] == CAR && s[1] == NL) 12130 ++s; 12131 *d++ = *s; 12132 } 12133 *d = NUL; 12134 } 12135 # endif 12136 #endif 12137 rettv->vval.v_string = res; 12138 res = NULL; 12139 } 12140 12141 errret: 12142 if (infile != NULL) 12143 { 12144 mch_remove(infile); 12145 vim_free(infile); 12146 } 12147 if (res != NULL) 12148 vim_free(res); 12149 if (list != NULL) 12150 list_free(list); 12151 } 12152 12153 /* 12154 * "system()" function 12155 */ 12156 static void 12157 f_system(typval_T *argvars, typval_T *rettv) 12158 { 12159 get_cmd_output_as_rettv(argvars, rettv, FALSE); 12160 } 12161 12162 /* 12163 * "systemlist()" function 12164 */ 12165 static void 12166 f_systemlist(typval_T *argvars, typval_T *rettv) 12167 { 12168 get_cmd_output_as_rettv(argvars, rettv, TRUE); 12169 } 12170 12171 /* 12172 * "tabpagebuflist()" function 12173 */ 12174 static void 12175 f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 12176 { 12177 #ifdef FEAT_WINDOWS 12178 tabpage_T *tp; 12179 win_T *wp = NULL; 12180 12181 if (argvars[0].v_type == VAR_UNKNOWN) 12182 wp = firstwin; 12183 else 12184 { 12185 tp = find_tabpage((int)get_tv_number(&argvars[0])); 12186 if (tp != NULL) 12187 wp = (tp == curtab) ? firstwin : tp->tp_firstwin; 12188 } 12189 if (wp != NULL && rettv_list_alloc(rettv) != FAIL) 12190 { 12191 for (; wp != NULL; wp = wp->w_next) 12192 if (list_append_number(rettv->vval.v_list, 12193 wp->w_buffer->b_fnum) == FAIL) 12194 break; 12195 } 12196 #endif 12197 } 12198 12199 12200 /* 12201 * "tabpagenr()" function 12202 */ 12203 static void 12204 f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv) 12205 { 12206 int nr = 1; 12207 #ifdef FEAT_WINDOWS 12208 char_u *arg; 12209 12210 if (argvars[0].v_type != VAR_UNKNOWN) 12211 { 12212 arg = get_tv_string_chk(&argvars[0]); 12213 nr = 0; 12214 if (arg != NULL) 12215 { 12216 if (STRCMP(arg, "$") == 0) 12217 nr = tabpage_index(NULL) - 1; 12218 else 12219 EMSG2(_(e_invexpr2), arg); 12220 } 12221 } 12222 else 12223 nr = tabpage_index(curtab); 12224 #endif 12225 rettv->vval.v_number = nr; 12226 } 12227 12228 12229 #ifdef FEAT_WINDOWS 12230 static int get_winnr(tabpage_T *tp, typval_T *argvar); 12231 12232 /* 12233 * Common code for tabpagewinnr() and winnr(). 12234 */ 12235 static int 12236 get_winnr(tabpage_T *tp, typval_T *argvar) 12237 { 12238 win_T *twin; 12239 int nr = 1; 12240 win_T *wp; 12241 char_u *arg; 12242 12243 twin = (tp == curtab) ? curwin : tp->tp_curwin; 12244 if (argvar->v_type != VAR_UNKNOWN) 12245 { 12246 arg = get_tv_string_chk(argvar); 12247 if (arg == NULL) 12248 nr = 0; /* type error; errmsg already given */ 12249 else if (STRCMP(arg, "$") == 0) 12250 twin = (tp == curtab) ? lastwin : tp->tp_lastwin; 12251 else if (STRCMP(arg, "#") == 0) 12252 { 12253 twin = (tp == curtab) ? prevwin : tp->tp_prevwin; 12254 if (twin == NULL) 12255 nr = 0; 12256 } 12257 else 12258 { 12259 EMSG2(_(e_invexpr2), arg); 12260 nr = 0; 12261 } 12262 } 12263 12264 if (nr > 0) 12265 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin; 12266 wp != twin; wp = wp->w_next) 12267 { 12268 if (wp == NULL) 12269 { 12270 /* didn't find it in this tabpage */ 12271 nr = 0; 12272 break; 12273 } 12274 ++nr; 12275 } 12276 return nr; 12277 } 12278 #endif 12279 12280 /* 12281 * "tabpagewinnr()" function 12282 */ 12283 static void 12284 f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv) 12285 { 12286 int nr = 1; 12287 #ifdef FEAT_WINDOWS 12288 tabpage_T *tp; 12289 12290 tp = find_tabpage((int)get_tv_number(&argvars[0])); 12291 if (tp == NULL) 12292 nr = 0; 12293 else 12294 nr = get_winnr(tp, &argvars[1]); 12295 #endif 12296 rettv->vval.v_number = nr; 12297 } 12298 12299 12300 /* 12301 * "tagfiles()" function 12302 */ 12303 static void 12304 f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv) 12305 { 12306 char_u *fname; 12307 tagname_T tn; 12308 int first; 12309 12310 if (rettv_list_alloc(rettv) == FAIL) 12311 return; 12312 fname = alloc(MAXPATHL); 12313 if (fname == NULL) 12314 return; 12315 12316 for (first = TRUE; ; first = FALSE) 12317 if (get_tagfname(&tn, first, fname) == FAIL 12318 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL) 12319 break; 12320 tagname_free(&tn); 12321 vim_free(fname); 12322 } 12323 12324 /* 12325 * "taglist()" function 12326 */ 12327 static void 12328 f_taglist(typval_T *argvars, typval_T *rettv) 12329 { 12330 char_u *fname = NULL; 12331 char_u *tag_pattern; 12332 12333 tag_pattern = get_tv_string(&argvars[0]); 12334 12335 rettv->vval.v_number = FALSE; 12336 if (*tag_pattern == NUL) 12337 return; 12338 12339 if (argvars[1].v_type != VAR_UNKNOWN) 12340 fname = get_tv_string(&argvars[1]); 12341 if (rettv_list_alloc(rettv) == OK) 12342 (void)get_tags(rettv->vval.v_list, tag_pattern, fname); 12343 } 12344 12345 /* 12346 * "tempname()" function 12347 */ 12348 static void 12349 f_tempname(typval_T *argvars UNUSED, typval_T *rettv) 12350 { 12351 static int x = 'A'; 12352 12353 rettv->v_type = VAR_STRING; 12354 rettv->vval.v_string = vim_tempname(x, FALSE); 12355 12356 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different 12357 * names. Skip 'I' and 'O', they are used for shell redirection. */ 12358 do 12359 { 12360 if (x == 'Z') 12361 x = '0'; 12362 else if (x == '9') 12363 x = 'A'; 12364 else 12365 { 12366 #ifdef EBCDIC 12367 if (x == 'I') 12368 x = 'J'; 12369 else if (x == 'R') 12370 x = 'S'; 12371 else 12372 #endif 12373 ++x; 12374 } 12375 } while (x == 'I' || x == 'O'); 12376 } 12377 12378 #ifdef FEAT_FLOAT 12379 /* 12380 * "tan()" function 12381 */ 12382 static void 12383 f_tan(typval_T *argvars, typval_T *rettv) 12384 { 12385 float_T f = 0.0; 12386 12387 rettv->v_type = VAR_FLOAT; 12388 if (get_float_arg(argvars, &f) == OK) 12389 rettv->vval.v_float = tan(f); 12390 else 12391 rettv->vval.v_float = 0.0; 12392 } 12393 12394 /* 12395 * "tanh()" function 12396 */ 12397 static void 12398 f_tanh(typval_T *argvars, typval_T *rettv) 12399 { 12400 float_T f = 0.0; 12401 12402 rettv->v_type = VAR_FLOAT; 12403 if (get_float_arg(argvars, &f) == OK) 12404 rettv->vval.v_float = tanh(f); 12405 else 12406 rettv->vval.v_float = 0.0; 12407 } 12408 #endif 12409 12410 /* 12411 * "test_alloc_fail(id, countdown, repeat)" function 12412 */ 12413 static void 12414 f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED) 12415 { 12416 if (argvars[0].v_type != VAR_NUMBER 12417 || argvars[0].vval.v_number <= 0 12418 || argvars[1].v_type != VAR_NUMBER 12419 || argvars[1].vval.v_number < 0 12420 || argvars[2].v_type != VAR_NUMBER) 12421 EMSG(_(e_invarg)); 12422 else 12423 { 12424 alloc_fail_id = argvars[0].vval.v_number; 12425 if (alloc_fail_id >= aid_last) 12426 EMSG(_(e_invarg)); 12427 alloc_fail_countdown = argvars[1].vval.v_number; 12428 alloc_fail_repeat = argvars[2].vval.v_number; 12429 did_outofmem_msg = FALSE; 12430 } 12431 } 12432 12433 /* 12434 * "test_autochdir()" 12435 */ 12436 static void 12437 f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 12438 { 12439 #if defined(FEAT_AUTOCHDIR) 12440 test_autochdir = TRUE; 12441 #endif 12442 } 12443 12444 /* 12445 * "test_disable({name}, {val})" function 12446 */ 12447 static void 12448 f_test_override(typval_T *argvars, typval_T *rettv UNUSED) 12449 { 12450 char_u *name = (char_u *)""; 12451 int val; 12452 static int save_starting = -1; 12453 12454 if (argvars[0].v_type != VAR_STRING 12455 || (argvars[1].v_type) != VAR_NUMBER) 12456 EMSG(_(e_invarg)); 12457 else 12458 { 12459 name = get_tv_string_chk(&argvars[0]); 12460 val = (int)get_tv_number(&argvars[1]); 12461 12462 if (STRCMP(name, (char_u *)"redraw") == 0) 12463 disable_redraw_for_testing = val; 12464 else if (STRCMP(name, (char_u *)"char_avail") == 0) 12465 disable_char_avail_for_testing = val; 12466 else if (STRCMP(name, (char_u *)"starting") == 0) 12467 { 12468 if (val) 12469 { 12470 if (save_starting < 0) 12471 save_starting = starting; 12472 starting = 0; 12473 } 12474 else 12475 { 12476 starting = save_starting; 12477 save_starting = -1; 12478 } 12479 } 12480 else if (STRCMP(name, (char_u *)"ALL") == 0) 12481 { 12482 disable_char_avail_for_testing = FALSE; 12483 disable_redraw_for_testing = FALSE; 12484 if (save_starting >= 0) 12485 { 12486 starting = save_starting; 12487 save_starting = -1; 12488 } 12489 } 12490 else 12491 EMSG2(_(e_invarg2), name); 12492 } 12493 } 12494 12495 /* 12496 * "test_garbagecollect_now()" function 12497 */ 12498 static void 12499 f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 12500 { 12501 /* This is dangerous, any Lists and Dicts used internally may be freed 12502 * while still in use. */ 12503 garbage_collect(TRUE); 12504 } 12505 12506 /* 12507 * "test_ignore_error()" function 12508 */ 12509 static void 12510 f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED) 12511 { 12512 ignore_error_for_testing(get_tv_string(&argvars[0])); 12513 } 12514 12515 #ifdef FEAT_JOB_CHANNEL 12516 static void 12517 f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv) 12518 { 12519 rettv->v_type = VAR_CHANNEL; 12520 rettv->vval.v_channel = NULL; 12521 } 12522 #endif 12523 12524 static void 12525 f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv) 12526 { 12527 rettv_dict_set(rettv, NULL); 12528 } 12529 12530 #ifdef FEAT_JOB_CHANNEL 12531 static void 12532 f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv) 12533 { 12534 rettv->v_type = VAR_JOB; 12535 rettv->vval.v_job = NULL; 12536 } 12537 #endif 12538 12539 static void 12540 f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv) 12541 { 12542 rettv_list_set(rettv, NULL); 12543 } 12544 12545 static void 12546 f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv) 12547 { 12548 rettv->v_type = VAR_PARTIAL; 12549 rettv->vval.v_partial = NULL; 12550 } 12551 12552 static void 12553 f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv) 12554 { 12555 rettv->v_type = VAR_STRING; 12556 rettv->vval.v_string = NULL; 12557 } 12558 12559 static void 12560 f_test_settime(typval_T *argvars, typval_T *rettv UNUSED) 12561 { 12562 time_for_testing = (time_t)get_tv_number(&argvars[0]); 12563 } 12564 12565 #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO) 12566 /* 12567 * Get a callback from "arg". It can be a Funcref or a function name. 12568 * When "arg" is zero return an empty string. 12569 * Return NULL for an invalid argument. 12570 */ 12571 char_u * 12572 get_callback(typval_T *arg, partial_T **pp) 12573 { 12574 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL) 12575 { 12576 *pp = arg->vval.v_partial; 12577 ++(*pp)->pt_refcount; 12578 return partial_name(*pp); 12579 } 12580 *pp = NULL; 12581 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING) 12582 { 12583 func_ref(arg->vval.v_string); 12584 return arg->vval.v_string; 12585 } 12586 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) 12587 return (char_u *)""; 12588 EMSG(_("E921: Invalid callback argument")); 12589 return NULL; 12590 } 12591 12592 /* 12593 * Unref/free "callback" and "partial" retured by get_callback(). 12594 */ 12595 void 12596 free_callback(char_u *callback, partial_T *partial) 12597 { 12598 if (partial != NULL) 12599 partial_unref(partial); 12600 else if (callback != NULL) 12601 { 12602 func_unref(callback); 12603 vim_free(callback); 12604 } 12605 } 12606 #endif 12607 12608 #ifdef FEAT_TIMERS 12609 /* 12610 * "timer_info([timer])" function 12611 */ 12612 static void 12613 f_timer_info(typval_T *argvars, typval_T *rettv) 12614 { 12615 timer_T *timer = NULL; 12616 12617 if (rettv_list_alloc(rettv) != OK) 12618 return; 12619 if (argvars[0].v_type != VAR_UNKNOWN) 12620 { 12621 if (argvars[0].v_type != VAR_NUMBER) 12622 EMSG(_(e_number_exp)); 12623 else 12624 { 12625 timer = find_timer((int)get_tv_number(&argvars[0])); 12626 if (timer != NULL) 12627 add_timer_info(rettv, timer); 12628 } 12629 } 12630 else 12631 add_timer_info_all(rettv); 12632 } 12633 12634 /* 12635 * "timer_pause(timer, paused)" function 12636 */ 12637 static void 12638 f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED) 12639 { 12640 timer_T *timer = NULL; 12641 int paused = (int)get_tv_number(&argvars[1]); 12642 12643 if (argvars[0].v_type != VAR_NUMBER) 12644 EMSG(_(e_number_exp)); 12645 else 12646 { 12647 timer = find_timer((int)get_tv_number(&argvars[0])); 12648 if (timer != NULL) 12649 timer->tr_paused = paused; 12650 } 12651 } 12652 12653 /* 12654 * "timer_start(time, callback [, options])" function 12655 */ 12656 static void 12657 f_timer_start(typval_T *argvars, typval_T *rettv) 12658 { 12659 long msec = (long)get_tv_number(&argvars[0]); 12660 timer_T *timer; 12661 int repeat = 0; 12662 char_u *callback; 12663 dict_T *dict; 12664 partial_T *partial; 12665 12666 rettv->vval.v_number = -1; 12667 if (check_secure()) 12668 return; 12669 if (argvars[2].v_type != VAR_UNKNOWN) 12670 { 12671 if (argvars[2].v_type != VAR_DICT 12672 || (dict = argvars[2].vval.v_dict) == NULL) 12673 { 12674 EMSG2(_(e_invarg2), get_tv_string(&argvars[2])); 12675 return; 12676 } 12677 if (dict_find(dict, (char_u *)"repeat", -1) != NULL) 12678 repeat = get_dict_number(dict, (char_u *)"repeat"); 12679 } 12680 12681 callback = get_callback(&argvars[1], &partial); 12682 if (callback == NULL) 12683 return; 12684 12685 timer = create_timer(msec, repeat); 12686 if (timer == NULL) 12687 free_callback(callback, partial); 12688 else 12689 { 12690 if (partial == NULL) 12691 timer->tr_callback = vim_strsave(callback); 12692 else 12693 /* pointer into the partial */ 12694 timer->tr_callback = callback; 12695 timer->tr_partial = partial; 12696 rettv->vval.v_number = (varnumber_T)timer->tr_id; 12697 } 12698 } 12699 12700 /* 12701 * "timer_stop(timer)" function 12702 */ 12703 static void 12704 f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED) 12705 { 12706 timer_T *timer; 12707 12708 if (argvars[0].v_type != VAR_NUMBER) 12709 { 12710 EMSG(_(e_number_exp)); 12711 return; 12712 } 12713 timer = find_timer((int)get_tv_number(&argvars[0])); 12714 if (timer != NULL) 12715 stop_timer(timer); 12716 } 12717 12718 /* 12719 * "timer_stopall()" function 12720 */ 12721 static void 12722 f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 12723 { 12724 stop_all_timers(); 12725 } 12726 #endif 12727 12728 /* 12729 * "tolower(string)" function 12730 */ 12731 static void 12732 f_tolower(typval_T *argvars, typval_T *rettv) 12733 { 12734 rettv->v_type = VAR_STRING; 12735 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0])); 12736 } 12737 12738 /* 12739 * "toupper(string)" function 12740 */ 12741 static void 12742 f_toupper(typval_T *argvars, typval_T *rettv) 12743 { 12744 rettv->v_type = VAR_STRING; 12745 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0])); 12746 } 12747 12748 /* 12749 * "tr(string, fromstr, tostr)" function 12750 */ 12751 static void 12752 f_tr(typval_T *argvars, typval_T *rettv) 12753 { 12754 char_u *in_str; 12755 char_u *fromstr; 12756 char_u *tostr; 12757 char_u *p; 12758 #ifdef FEAT_MBYTE 12759 int inlen; 12760 int fromlen; 12761 int tolen; 12762 int idx; 12763 char_u *cpstr; 12764 int cplen; 12765 int first = TRUE; 12766 #endif 12767 char_u buf[NUMBUFLEN]; 12768 char_u buf2[NUMBUFLEN]; 12769 garray_T ga; 12770 12771 in_str = get_tv_string(&argvars[0]); 12772 fromstr = get_tv_string_buf_chk(&argvars[1], buf); 12773 tostr = get_tv_string_buf_chk(&argvars[2], buf2); 12774 12775 /* Default return value: empty string. */ 12776 rettv->v_type = VAR_STRING; 12777 rettv->vval.v_string = NULL; 12778 if (fromstr == NULL || tostr == NULL) 12779 return; /* type error; errmsg already given */ 12780 ga_init2(&ga, (int)sizeof(char), 80); 12781 12782 #ifdef FEAT_MBYTE 12783 if (!has_mbyte) 12784 #endif 12785 /* not multi-byte: fromstr and tostr must be the same length */ 12786 if (STRLEN(fromstr) != STRLEN(tostr)) 12787 { 12788 #ifdef FEAT_MBYTE 12789 error: 12790 #endif 12791 EMSG2(_(e_invarg2), fromstr); 12792 ga_clear(&ga); 12793 return; 12794 } 12795 12796 /* fromstr and tostr have to contain the same number of chars */ 12797 while (*in_str != NUL) 12798 { 12799 #ifdef FEAT_MBYTE 12800 if (has_mbyte) 12801 { 12802 inlen = (*mb_ptr2len)(in_str); 12803 cpstr = in_str; 12804 cplen = inlen; 12805 idx = 0; 12806 for (p = fromstr; *p != NUL; p += fromlen) 12807 { 12808 fromlen = (*mb_ptr2len)(p); 12809 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0) 12810 { 12811 for (p = tostr; *p != NUL; p += tolen) 12812 { 12813 tolen = (*mb_ptr2len)(p); 12814 if (idx-- == 0) 12815 { 12816 cplen = tolen; 12817 cpstr = p; 12818 break; 12819 } 12820 } 12821 if (*p == NUL) /* tostr is shorter than fromstr */ 12822 goto error; 12823 break; 12824 } 12825 ++idx; 12826 } 12827 12828 if (first && cpstr == in_str) 12829 { 12830 /* Check that fromstr and tostr have the same number of 12831 * (multi-byte) characters. Done only once when a character 12832 * of in_str doesn't appear in fromstr. */ 12833 first = FALSE; 12834 for (p = tostr; *p != NUL; p += tolen) 12835 { 12836 tolen = (*mb_ptr2len)(p); 12837 --idx; 12838 } 12839 if (idx != 0) 12840 goto error; 12841 } 12842 12843 (void)ga_grow(&ga, cplen); 12844 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen); 12845 ga.ga_len += cplen; 12846 12847 in_str += inlen; 12848 } 12849 else 12850 #endif 12851 { 12852 /* When not using multi-byte chars we can do it faster. */ 12853 p = vim_strchr(fromstr, *in_str); 12854 if (p != NULL) 12855 ga_append(&ga, tostr[p - fromstr]); 12856 else 12857 ga_append(&ga, *in_str); 12858 ++in_str; 12859 } 12860 } 12861 12862 /* add a terminating NUL */ 12863 (void)ga_grow(&ga, 1); 12864 ga_append(&ga, NUL); 12865 12866 rettv->vval.v_string = ga.ga_data; 12867 } 12868 12869 #ifdef FEAT_FLOAT 12870 /* 12871 * "trunc({float})" function 12872 */ 12873 static void 12874 f_trunc(typval_T *argvars, typval_T *rettv) 12875 { 12876 float_T f = 0.0; 12877 12878 rettv->v_type = VAR_FLOAT; 12879 if (get_float_arg(argvars, &f) == OK) 12880 /* trunc() is not in C90, use floor() or ceil() instead. */ 12881 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f); 12882 else 12883 rettv->vval.v_float = 0.0; 12884 } 12885 #endif 12886 12887 /* 12888 * "type(expr)" function 12889 */ 12890 static void 12891 f_type(typval_T *argvars, typval_T *rettv) 12892 { 12893 int n = -1; 12894 12895 switch (argvars[0].v_type) 12896 { 12897 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break; 12898 case VAR_STRING: n = VAR_TYPE_STRING; break; 12899 case VAR_PARTIAL: 12900 case VAR_FUNC: n = VAR_TYPE_FUNC; break; 12901 case VAR_LIST: n = VAR_TYPE_LIST; break; 12902 case VAR_DICT: n = VAR_TYPE_DICT; break; 12903 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break; 12904 case VAR_SPECIAL: 12905 if (argvars[0].vval.v_number == VVAL_FALSE 12906 || argvars[0].vval.v_number == VVAL_TRUE) 12907 n = VAR_TYPE_BOOL; 12908 else 12909 n = VAR_TYPE_NONE; 12910 break; 12911 case VAR_JOB: n = VAR_TYPE_JOB; break; 12912 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break; 12913 case VAR_UNKNOWN: 12914 internal_error("f_type(UNKNOWN)"); 12915 n = -1; 12916 break; 12917 } 12918 rettv->vval.v_number = n; 12919 } 12920 12921 /* 12922 * "undofile(name)" function 12923 */ 12924 static void 12925 f_undofile(typval_T *argvars UNUSED, typval_T *rettv) 12926 { 12927 rettv->v_type = VAR_STRING; 12928 #ifdef FEAT_PERSISTENT_UNDO 12929 { 12930 char_u *fname = get_tv_string(&argvars[0]); 12931 12932 if (*fname == NUL) 12933 { 12934 /* If there is no file name there will be no undo file. */ 12935 rettv->vval.v_string = NULL; 12936 } 12937 else 12938 { 12939 char_u *ffname = FullName_save(fname, FALSE); 12940 12941 if (ffname != NULL) 12942 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE); 12943 vim_free(ffname); 12944 } 12945 } 12946 #else 12947 rettv->vval.v_string = NULL; 12948 #endif 12949 } 12950 12951 /* 12952 * "undotree()" function 12953 */ 12954 static void 12955 f_undotree(typval_T *argvars UNUSED, typval_T *rettv) 12956 { 12957 if (rettv_dict_alloc(rettv) == OK) 12958 { 12959 dict_T *dict = rettv->vval.v_dict; 12960 list_T *list; 12961 12962 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL); 12963 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL); 12964 dict_add_nr_str(dict, "save_last", 12965 (long)curbuf->b_u_save_nr_last, NULL); 12966 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL); 12967 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL); 12968 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL); 12969 12970 list = list_alloc(); 12971 if (list != NULL) 12972 { 12973 u_eval_tree(curbuf->b_u_oldhead, list); 12974 dict_add_list(dict, "entries", list); 12975 } 12976 } 12977 } 12978 12979 /* 12980 * "values(dict)" function 12981 */ 12982 static void 12983 f_values(typval_T *argvars, typval_T *rettv) 12984 { 12985 dict_list(argvars, rettv, 1); 12986 } 12987 12988 /* 12989 * "virtcol(string)" function 12990 */ 12991 static void 12992 f_virtcol(typval_T *argvars, typval_T *rettv) 12993 { 12994 colnr_T vcol = 0; 12995 pos_T *fp; 12996 int fnum = curbuf->b_fnum; 12997 12998 fp = var2fpos(&argvars[0], FALSE, &fnum); 12999 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count 13000 && fnum == curbuf->b_fnum) 13001 { 13002 getvvcol(curwin, fp, NULL, NULL, &vcol); 13003 ++vcol; 13004 } 13005 13006 rettv->vval.v_number = vcol; 13007 } 13008 13009 /* 13010 * "visualmode()" function 13011 */ 13012 static void 13013 f_visualmode(typval_T *argvars, typval_T *rettv) 13014 { 13015 char_u str[2]; 13016 13017 rettv->v_type = VAR_STRING; 13018 str[0] = curbuf->b_visual_mode_eval; 13019 str[1] = NUL; 13020 rettv->vval.v_string = vim_strsave(str); 13021 13022 /* A non-zero number or non-empty string argument: reset mode. */ 13023 if (non_zero_arg(&argvars[0])) 13024 curbuf->b_visual_mode_eval = NUL; 13025 } 13026 13027 /* 13028 * "wildmenumode()" function 13029 */ 13030 static void 13031 f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 13032 { 13033 #ifdef FEAT_WILDMENU 13034 if (wild_menu_showing) 13035 rettv->vval.v_number = 1; 13036 #endif 13037 } 13038 13039 /* 13040 * "winbufnr(nr)" function 13041 */ 13042 static void 13043 f_winbufnr(typval_T *argvars, typval_T *rettv) 13044 { 13045 win_T *wp; 13046 13047 wp = find_win_by_nr(&argvars[0], NULL); 13048 if (wp == NULL) 13049 rettv->vval.v_number = -1; 13050 else 13051 rettv->vval.v_number = wp->w_buffer->b_fnum; 13052 } 13053 13054 /* 13055 * "wincol()" function 13056 */ 13057 static void 13058 f_wincol(typval_T *argvars UNUSED, typval_T *rettv) 13059 { 13060 validate_cursor(); 13061 rettv->vval.v_number = curwin->w_wcol + 1; 13062 } 13063 13064 /* 13065 * "winheight(nr)" function 13066 */ 13067 static void 13068 f_winheight(typval_T *argvars, typval_T *rettv) 13069 { 13070 win_T *wp; 13071 13072 wp = find_win_by_nr(&argvars[0], NULL); 13073 if (wp == NULL) 13074 rettv->vval.v_number = -1; 13075 else 13076 rettv->vval.v_number = wp->w_height; 13077 } 13078 13079 /* 13080 * "winline()" function 13081 */ 13082 static void 13083 f_winline(typval_T *argvars UNUSED, typval_T *rettv) 13084 { 13085 validate_cursor(); 13086 rettv->vval.v_number = curwin->w_wrow + 1; 13087 } 13088 13089 /* 13090 * "winnr()" function 13091 */ 13092 static void 13093 f_winnr(typval_T *argvars UNUSED, typval_T *rettv) 13094 { 13095 int nr = 1; 13096 13097 #ifdef FEAT_WINDOWS 13098 nr = get_winnr(curtab, &argvars[0]); 13099 #endif 13100 rettv->vval.v_number = nr; 13101 } 13102 13103 /* 13104 * "winrestcmd()" function 13105 */ 13106 static void 13107 f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv) 13108 { 13109 #ifdef FEAT_WINDOWS 13110 win_T *wp; 13111 int winnr = 1; 13112 garray_T ga; 13113 char_u buf[50]; 13114 13115 ga_init2(&ga, (int)sizeof(char), 70); 13116 FOR_ALL_WINDOWS(wp) 13117 { 13118 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height); 13119 ga_concat(&ga, buf); 13120 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width); 13121 ga_concat(&ga, buf); 13122 ++winnr; 13123 } 13124 ga_append(&ga, NUL); 13125 13126 rettv->vval.v_string = ga.ga_data; 13127 #else 13128 rettv->vval.v_string = NULL; 13129 #endif 13130 rettv->v_type = VAR_STRING; 13131 } 13132 13133 /* 13134 * "winrestview()" function 13135 */ 13136 static void 13137 f_winrestview(typval_T *argvars, typval_T *rettv UNUSED) 13138 { 13139 dict_T *dict; 13140 13141 if (argvars[0].v_type != VAR_DICT 13142 || (dict = argvars[0].vval.v_dict) == NULL) 13143 EMSG(_(e_invarg)); 13144 else 13145 { 13146 if (dict_find(dict, (char_u *)"lnum", -1) != NULL) 13147 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum"); 13148 if (dict_find(dict, (char_u *)"col", -1) != NULL) 13149 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col"); 13150 #ifdef FEAT_VIRTUALEDIT 13151 if (dict_find(dict, (char_u *)"coladd", -1) != NULL) 13152 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd"); 13153 #endif 13154 if (dict_find(dict, (char_u *)"curswant", -1) != NULL) 13155 { 13156 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant"); 13157 curwin->w_set_curswant = FALSE; 13158 } 13159 13160 if (dict_find(dict, (char_u *)"topline", -1) != NULL) 13161 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline")); 13162 #ifdef FEAT_DIFF 13163 if (dict_find(dict, (char_u *)"topfill", -1) != NULL) 13164 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill"); 13165 #endif 13166 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL) 13167 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol"); 13168 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL) 13169 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol"); 13170 13171 check_cursor(); 13172 win_new_height(curwin, curwin->w_height); 13173 # ifdef FEAT_WINDOWS 13174 win_new_width(curwin, W_WIDTH(curwin)); 13175 # endif 13176 changed_window_setting(); 13177 13178 if (curwin->w_topline <= 0) 13179 curwin->w_topline = 1; 13180 if (curwin->w_topline > curbuf->b_ml.ml_line_count) 13181 curwin->w_topline = curbuf->b_ml.ml_line_count; 13182 #ifdef FEAT_DIFF 13183 check_topfill(curwin, TRUE); 13184 #endif 13185 } 13186 } 13187 13188 /* 13189 * "winsaveview()" function 13190 */ 13191 static void 13192 f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv) 13193 { 13194 dict_T *dict; 13195 13196 if (rettv_dict_alloc(rettv) == FAIL) 13197 return; 13198 dict = rettv->vval.v_dict; 13199 13200 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL); 13201 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL); 13202 #ifdef FEAT_VIRTUALEDIT 13203 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL); 13204 #endif 13205 update_curswant(); 13206 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL); 13207 13208 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL); 13209 #ifdef FEAT_DIFF 13210 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL); 13211 #endif 13212 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL); 13213 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL); 13214 } 13215 13216 /* 13217 * "winwidth(nr)" function 13218 */ 13219 static void 13220 f_winwidth(typval_T *argvars, typval_T *rettv) 13221 { 13222 win_T *wp; 13223 13224 wp = find_win_by_nr(&argvars[0], NULL); 13225 if (wp == NULL) 13226 rettv->vval.v_number = -1; 13227 else 13228 #ifdef FEAT_WINDOWS 13229 rettv->vval.v_number = wp->w_width; 13230 #else 13231 rettv->vval.v_number = Columns; 13232 #endif 13233 } 13234 13235 /* 13236 * "wordcount()" function 13237 */ 13238 static void 13239 f_wordcount(typval_T *argvars UNUSED, typval_T *rettv) 13240 { 13241 if (rettv_dict_alloc(rettv) == FAIL) 13242 return; 13243 cursor_pos_info(rettv->vval.v_dict); 13244 } 13245 13246 /* 13247 * "writefile()" function 13248 */ 13249 static void 13250 f_writefile(typval_T *argvars, typval_T *rettv) 13251 { 13252 int binary = FALSE; 13253 int append = FALSE; 13254 char_u *fname; 13255 FILE *fd; 13256 int ret = 0; 13257 listitem_T *li; 13258 list_T *list; 13259 13260 rettv->vval.v_number = -1; 13261 if (check_restricted() || check_secure()) 13262 return; 13263 13264 if (argvars[0].v_type != VAR_LIST) 13265 { 13266 EMSG2(_(e_listarg), "writefile()"); 13267 return; 13268 } 13269 list = argvars[0].vval.v_list; 13270 if (list == NULL) 13271 return; 13272 for (li = list->lv_first; li != NULL; li = li->li_next) 13273 if (get_tv_string_chk(&li->li_tv) == NULL) 13274 return; 13275 13276 if (argvars[2].v_type != VAR_UNKNOWN) 13277 { 13278 char_u *arg2 = get_tv_string_chk(&argvars[2]); 13279 13280 if (arg2 == NULL) 13281 return; 13282 if (vim_strchr(arg2, 'b') != NULL) 13283 binary = TRUE; 13284 if (vim_strchr(arg2, 'a') != NULL) 13285 append = TRUE; 13286 } 13287 13288 fname = get_tv_string_chk(&argvars[1]); 13289 if (fname == NULL) 13290 return; 13291 13292 /* Always open the file in binary mode, library functions have a mind of 13293 * their own about CR-LF conversion. */ 13294 if (*fname == NUL || (fd = mch_fopen((char *)fname, 13295 append ? APPENDBIN : WRITEBIN)) == NULL) 13296 { 13297 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname); 13298 ret = -1; 13299 } 13300 else 13301 { 13302 if (write_list(fd, list, binary) == FAIL) 13303 ret = -1; 13304 fclose(fd); 13305 } 13306 13307 rettv->vval.v_number = ret; 13308 } 13309 13310 /* 13311 * "xor(expr, expr)" function 13312 */ 13313 static void 13314 f_xor(typval_T *argvars, typval_T *rettv) 13315 { 13316 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) 13317 ^ get_tv_number_chk(&argvars[1], NULL); 13318 } 13319 13320 13321 #endif /* FEAT_EVAL */ 13322