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_X 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 static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob"); 33 static char *e_stringreq = N_("E928: String required"); 34 35 #ifdef FEAT_FLOAT 36 static void f_abs(typval_T *argvars, typval_T *rettv); 37 static void f_acos(typval_T *argvars, typval_T *rettv); 38 #endif 39 static void f_add(typval_T *argvars, typval_T *rettv); 40 static void f_and(typval_T *argvars, typval_T *rettv); 41 static void f_append(typval_T *argvars, typval_T *rettv); 42 static void f_appendbufline(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_beeps(typval_T *argvars, typval_T *rettv); 48 static void f_assert_equal(typval_T *argvars, typval_T *rettv); 49 static void f_assert_equalfile(typval_T *argvars, typval_T *rettv); 50 static void f_assert_exception(typval_T *argvars, typval_T *rettv); 51 static void f_assert_fails(typval_T *argvars, typval_T *rettv); 52 static void f_assert_false(typval_T *argvars, typval_T *rettv); 53 static void f_assert_inrange(typval_T *argvars, typval_T *rettv); 54 static void f_assert_match(typval_T *argvars, typval_T *rettv); 55 static void f_assert_notequal(typval_T *argvars, typval_T *rettv); 56 static void f_assert_notmatch(typval_T *argvars, typval_T *rettv); 57 static void f_assert_report(typval_T *argvars, typval_T *rettv); 58 static void f_assert_true(typval_T *argvars, typval_T *rettv); 59 #ifdef FEAT_FLOAT 60 static void f_asin(typval_T *argvars, typval_T *rettv); 61 static void f_atan(typval_T *argvars, typval_T *rettv); 62 static void f_atan2(typval_T *argvars, typval_T *rettv); 63 #endif 64 #ifdef FEAT_BEVAL 65 static void f_balloon_show(typval_T *argvars, typval_T *rettv); 66 # if defined(FEAT_BEVAL_TERM) 67 static void f_balloon_split(typval_T *argvars, typval_T *rettv); 68 # endif 69 #endif 70 static void f_browse(typval_T *argvars, typval_T *rettv); 71 static void f_browsedir(typval_T *argvars, typval_T *rettv); 72 static void f_bufexists(typval_T *argvars, typval_T *rettv); 73 static void f_buflisted(typval_T *argvars, typval_T *rettv); 74 static void f_bufloaded(typval_T *argvars, typval_T *rettv); 75 static void f_bufname(typval_T *argvars, typval_T *rettv); 76 static void f_bufnr(typval_T *argvars, typval_T *rettv); 77 static void f_bufwinid(typval_T *argvars, typval_T *rettv); 78 static void f_bufwinnr(typval_T *argvars, typval_T *rettv); 79 static void f_byte2line(typval_T *argvars, typval_T *rettv); 80 static void byteidx(typval_T *argvars, typval_T *rettv, int comp); 81 static void f_byteidx(typval_T *argvars, typval_T *rettv); 82 static void f_byteidxcomp(typval_T *argvars, typval_T *rettv); 83 static void f_call(typval_T *argvars, typval_T *rettv); 84 #ifdef FEAT_FLOAT 85 static void f_ceil(typval_T *argvars, typval_T *rettv); 86 #endif 87 #ifdef FEAT_JOB_CHANNEL 88 static void f_ch_canread(typval_T *argvars, typval_T *rettv); 89 static void f_ch_close(typval_T *argvars, typval_T *rettv); 90 static void f_ch_close_in(typval_T *argvars, typval_T *rettv); 91 static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv); 92 static void f_ch_evalraw(typval_T *argvars, typval_T *rettv); 93 static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv); 94 static void f_ch_getjob(typval_T *argvars, typval_T *rettv); 95 static void f_ch_info(typval_T *argvars, typval_T *rettv); 96 static void f_ch_log(typval_T *argvars, typval_T *rettv); 97 static void f_ch_logfile(typval_T *argvars, typval_T *rettv); 98 static void f_ch_open(typval_T *argvars, typval_T *rettv); 99 static void f_ch_read(typval_T *argvars, typval_T *rettv); 100 static void f_ch_readblob(typval_T *argvars, typval_T *rettv); 101 static void f_ch_readraw(typval_T *argvars, typval_T *rettv); 102 static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv); 103 static void f_ch_sendraw(typval_T *argvars, typval_T *rettv); 104 static void f_ch_setoptions(typval_T *argvars, typval_T *rettv); 105 static void f_ch_status(typval_T *argvars, typval_T *rettv); 106 #endif 107 static void f_changenr(typval_T *argvars, typval_T *rettv); 108 static void f_char2nr(typval_T *argvars, typval_T *rettv); 109 static void f_cindent(typval_T *argvars, typval_T *rettv); 110 static void f_clearmatches(typval_T *argvars, typval_T *rettv); 111 static void f_col(typval_T *argvars, typval_T *rettv); 112 #if defined(FEAT_INS_EXPAND) 113 static void f_complete(typval_T *argvars, typval_T *rettv); 114 static void f_complete_add(typval_T *argvars, typval_T *rettv); 115 static void f_complete_check(typval_T *argvars, typval_T *rettv); 116 #endif 117 static void f_confirm(typval_T *argvars, typval_T *rettv); 118 static void f_copy(typval_T *argvars, typval_T *rettv); 119 #ifdef FEAT_FLOAT 120 static void f_cos(typval_T *argvars, typval_T *rettv); 121 static void f_cosh(typval_T *argvars, typval_T *rettv); 122 #endif 123 static void f_count(typval_T *argvars, typval_T *rettv); 124 static void f_cscope_connection(typval_T *argvars, typval_T *rettv); 125 static void f_cursor(typval_T *argsvars, typval_T *rettv); 126 #ifdef WIN3264 127 static void f_debugbreak(typval_T *argvars, typval_T *rettv); 128 #endif 129 static void f_deepcopy(typval_T *argvars, typval_T *rettv); 130 static void f_delete(typval_T *argvars, typval_T *rettv); 131 static void f_deletebufline(typval_T *argvars, typval_T *rettv); 132 static void f_did_filetype(typval_T *argvars, typval_T *rettv); 133 static void f_diff_filler(typval_T *argvars, typval_T *rettv); 134 static void f_diff_hlID(typval_T *argvars, typval_T *rettv); 135 static void f_empty(typval_T *argvars, typval_T *rettv); 136 static void f_escape(typval_T *argvars, typval_T *rettv); 137 static void f_eval(typval_T *argvars, typval_T *rettv); 138 static void f_eventhandler(typval_T *argvars, typval_T *rettv); 139 static void f_executable(typval_T *argvars, typval_T *rettv); 140 static void f_execute(typval_T *argvars, typval_T *rettv); 141 static void f_exepath(typval_T *argvars, typval_T *rettv); 142 static void f_exists(typval_T *argvars, typval_T *rettv); 143 #ifdef FEAT_FLOAT 144 static void f_exp(typval_T *argvars, typval_T *rettv); 145 #endif 146 static void f_expand(typval_T *argvars, typval_T *rettv); 147 static void f_extend(typval_T *argvars, typval_T *rettv); 148 static void f_feedkeys(typval_T *argvars, typval_T *rettv); 149 static void f_filereadable(typval_T *argvars, typval_T *rettv); 150 static void f_filewritable(typval_T *argvars, typval_T *rettv); 151 static void f_filter(typval_T *argvars, typval_T *rettv); 152 static void f_finddir(typval_T *argvars, typval_T *rettv); 153 static void f_findfile(typval_T *argvars, typval_T *rettv); 154 #ifdef FEAT_FLOAT 155 static void f_float2nr(typval_T *argvars, typval_T *rettv); 156 static void f_floor(typval_T *argvars, typval_T *rettv); 157 static void f_fmod(typval_T *argvars, typval_T *rettv); 158 #endif 159 static void f_fnameescape(typval_T *argvars, typval_T *rettv); 160 static void f_fnamemodify(typval_T *argvars, typval_T *rettv); 161 static void f_foldclosed(typval_T *argvars, typval_T *rettv); 162 static void f_foldclosedend(typval_T *argvars, typval_T *rettv); 163 static void f_foldlevel(typval_T *argvars, typval_T *rettv); 164 static void f_foldtext(typval_T *argvars, typval_T *rettv); 165 static void f_foldtextresult(typval_T *argvars, typval_T *rettv); 166 static void f_foreground(typval_T *argvars, typval_T *rettv); 167 static void f_funcref(typval_T *argvars, typval_T *rettv); 168 static void f_function(typval_T *argvars, typval_T *rettv); 169 static void f_garbagecollect(typval_T *argvars, typval_T *rettv); 170 static void f_get(typval_T *argvars, typval_T *rettv); 171 static void f_getbufinfo(typval_T *argvars, typval_T *rettv); 172 static void f_getbufline(typval_T *argvars, typval_T *rettv); 173 static void f_getbufvar(typval_T *argvars, typval_T *rettv); 174 static void f_getchangelist(typval_T *argvars, typval_T *rettv); 175 static void f_getchar(typval_T *argvars, typval_T *rettv); 176 static void f_getcharmod(typval_T *argvars, typval_T *rettv); 177 static void f_getcharsearch(typval_T *argvars, typval_T *rettv); 178 static void f_getcmdline(typval_T *argvars, typval_T *rettv); 179 #if defined(FEAT_CMDL_COMPL) 180 static void f_getcompletion(typval_T *argvars, typval_T *rettv); 181 #endif 182 static void f_getcmdpos(typval_T *argvars, typval_T *rettv); 183 static void f_getcmdtype(typval_T *argvars, typval_T *rettv); 184 static void f_getcmdwintype(typval_T *argvars, typval_T *rettv); 185 static void f_getcwd(typval_T *argvars, typval_T *rettv); 186 static void f_getfontname(typval_T *argvars, typval_T *rettv); 187 static void f_getfperm(typval_T *argvars, typval_T *rettv); 188 static void f_getfsize(typval_T *argvars, typval_T *rettv); 189 static void f_getftime(typval_T *argvars, typval_T *rettv); 190 static void f_getftype(typval_T *argvars, typval_T *rettv); 191 static void f_getjumplist(typval_T *argvars, typval_T *rettv); 192 static void f_getline(typval_T *argvars, typval_T *rettv); 193 static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED); 194 static void f_getmatches(typval_T *argvars, typval_T *rettv); 195 static void f_getpid(typval_T *argvars, typval_T *rettv); 196 static void f_getcurpos(typval_T *argvars, typval_T *rettv); 197 static void f_getpos(typval_T *argvars, typval_T *rettv); 198 static void f_getqflist(typval_T *argvars, typval_T *rettv); 199 static void f_getreg(typval_T *argvars, typval_T *rettv); 200 static void f_getregtype(typval_T *argvars, typval_T *rettv); 201 static void f_gettabinfo(typval_T *argvars, typval_T *rettv); 202 static void f_gettabvar(typval_T *argvars, typval_T *rettv); 203 static void f_gettabwinvar(typval_T *argvars, typval_T *rettv); 204 static void f_gettagstack(typval_T *argvars, typval_T *rettv); 205 static void f_getwininfo(typval_T *argvars, typval_T *rettv); 206 static void f_getwinpos(typval_T *argvars, typval_T *rettv); 207 static void f_getwinposx(typval_T *argvars, typval_T *rettv); 208 static void f_getwinposy(typval_T *argvars, typval_T *rettv); 209 static void f_getwinvar(typval_T *argvars, typval_T *rettv); 210 static void f_glob(typval_T *argvars, typval_T *rettv); 211 static void f_globpath(typval_T *argvars, typval_T *rettv); 212 static void f_glob2regpat(typval_T *argvars, typval_T *rettv); 213 static void f_has(typval_T *argvars, typval_T *rettv); 214 static void f_has_key(typval_T *argvars, typval_T *rettv); 215 static void f_haslocaldir(typval_T *argvars, typval_T *rettv); 216 static void f_hasmapto(typval_T *argvars, typval_T *rettv); 217 static void f_histadd(typval_T *argvars, typval_T *rettv); 218 static void f_histdel(typval_T *argvars, typval_T *rettv); 219 static void f_histget(typval_T *argvars, typval_T *rettv); 220 static void f_histnr(typval_T *argvars, typval_T *rettv); 221 static void f_hlID(typval_T *argvars, typval_T *rettv); 222 static void f_hlexists(typval_T *argvars, typval_T *rettv); 223 static void f_hostname(typval_T *argvars, typval_T *rettv); 224 static void f_iconv(typval_T *argvars, typval_T *rettv); 225 static void f_indent(typval_T *argvars, typval_T *rettv); 226 static void f_index(typval_T *argvars, typval_T *rettv); 227 static void f_input(typval_T *argvars, typval_T *rettv); 228 static void f_inputdialog(typval_T *argvars, typval_T *rettv); 229 static void f_inputlist(typval_T *argvars, typval_T *rettv); 230 static void f_inputrestore(typval_T *argvars, typval_T *rettv); 231 static void f_inputsave(typval_T *argvars, typval_T *rettv); 232 static void f_inputsecret(typval_T *argvars, typval_T *rettv); 233 static void f_insert(typval_T *argvars, typval_T *rettv); 234 static void f_invert(typval_T *argvars, typval_T *rettv); 235 static void f_isdirectory(typval_T *argvars, typval_T *rettv); 236 static void f_islocked(typval_T *argvars, typval_T *rettv); 237 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) 238 static void f_isnan(typval_T *argvars, typval_T *rettv); 239 #endif 240 static void f_items(typval_T *argvars, typval_T *rettv); 241 #ifdef FEAT_JOB_CHANNEL 242 static void f_job_getchannel(typval_T *argvars, typval_T *rettv); 243 static void f_job_info(typval_T *argvars, typval_T *rettv); 244 static void f_job_setoptions(typval_T *argvars, typval_T *rettv); 245 static void f_job_start(typval_T *argvars, typval_T *rettv); 246 static void f_job_stop(typval_T *argvars, typval_T *rettv); 247 static void f_job_status(typval_T *argvars, typval_T *rettv); 248 #endif 249 static void f_join(typval_T *argvars, typval_T *rettv); 250 static void f_js_decode(typval_T *argvars, typval_T *rettv); 251 static void f_js_encode(typval_T *argvars, typval_T *rettv); 252 static void f_json_decode(typval_T *argvars, typval_T *rettv); 253 static void f_json_encode(typval_T *argvars, typval_T *rettv); 254 static void f_keys(typval_T *argvars, typval_T *rettv); 255 static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv); 256 static void f_len(typval_T *argvars, typval_T *rettv); 257 static void f_libcall(typval_T *argvars, typval_T *rettv); 258 static void f_libcallnr(typval_T *argvars, typval_T *rettv); 259 static void f_line(typval_T *argvars, typval_T *rettv); 260 static void f_line2byte(typval_T *argvars, typval_T *rettv); 261 static void f_lispindent(typval_T *argvars, typval_T *rettv); 262 static void f_localtime(typval_T *argvars, typval_T *rettv); 263 #ifdef FEAT_FLOAT 264 static void f_log(typval_T *argvars, typval_T *rettv); 265 static void f_log10(typval_T *argvars, typval_T *rettv); 266 #endif 267 #ifdef FEAT_LUA 268 static void f_luaeval(typval_T *argvars, typval_T *rettv); 269 #endif 270 static void f_map(typval_T *argvars, typval_T *rettv); 271 static void f_maparg(typval_T *argvars, typval_T *rettv); 272 static void f_mapcheck(typval_T *argvars, typval_T *rettv); 273 static void f_match(typval_T *argvars, typval_T *rettv); 274 static void f_matchadd(typval_T *argvars, typval_T *rettv); 275 static void f_matchaddpos(typval_T *argvars, typval_T *rettv); 276 static void f_matcharg(typval_T *argvars, typval_T *rettv); 277 static void f_matchdelete(typval_T *argvars, typval_T *rettv); 278 static void f_matchend(typval_T *argvars, typval_T *rettv); 279 static void f_matchlist(typval_T *argvars, typval_T *rettv); 280 static void f_matchstr(typval_T *argvars, typval_T *rettv); 281 static void f_matchstrpos(typval_T *argvars, typval_T *rettv); 282 static void f_max(typval_T *argvars, typval_T *rettv); 283 static void f_min(typval_T *argvars, typval_T *rettv); 284 #ifdef vim_mkdir 285 static void f_mkdir(typval_T *argvars, typval_T *rettv); 286 #endif 287 static void f_mode(typval_T *argvars, typval_T *rettv); 288 #ifdef FEAT_MZSCHEME 289 static void f_mzeval(typval_T *argvars, typval_T *rettv); 290 #endif 291 static void f_nextnonblank(typval_T *argvars, typval_T *rettv); 292 static void f_nr2char(typval_T *argvars, typval_T *rettv); 293 static void f_or(typval_T *argvars, typval_T *rettv); 294 static void f_pathshorten(typval_T *argvars, typval_T *rettv); 295 #ifdef FEAT_PERL 296 static void f_perleval(typval_T *argvars, typval_T *rettv); 297 #endif 298 #ifdef FEAT_FLOAT 299 static void f_pow(typval_T *argvars, typval_T *rettv); 300 #endif 301 static void f_prevnonblank(typval_T *argvars, typval_T *rettv); 302 static void f_printf(typval_T *argvars, typval_T *rettv); 303 #ifdef FEAT_JOB_CHANNEL 304 static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv); 305 static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv); 306 static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv); 307 #endif 308 static void f_pumvisible(typval_T *argvars, typval_T *rettv); 309 #ifdef FEAT_PYTHON3 310 static void f_py3eval(typval_T *argvars, typval_T *rettv); 311 #endif 312 #ifdef FEAT_PYTHON 313 static void f_pyeval(typval_T *argvars, typval_T *rettv); 314 #endif 315 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) 316 static void f_pyxeval(typval_T *argvars, typval_T *rettv); 317 #endif 318 static void f_range(typval_T *argvars, typval_T *rettv); 319 static void f_readfile(typval_T *argvars, typval_T *rettv); 320 static void f_reg_executing(typval_T *argvars, typval_T *rettv); 321 static void f_reg_recording(typval_T *argvars, typval_T *rettv); 322 static void f_reltime(typval_T *argvars, typval_T *rettv); 323 #ifdef FEAT_FLOAT 324 static void f_reltimefloat(typval_T *argvars, typval_T *rettv); 325 #endif 326 static void f_reltimestr(typval_T *argvars, typval_T *rettv); 327 static void f_remote_expr(typval_T *argvars, typval_T *rettv); 328 static void f_remote_foreground(typval_T *argvars, typval_T *rettv); 329 static void f_remote_peek(typval_T *argvars, typval_T *rettv); 330 static void f_remote_read(typval_T *argvars, typval_T *rettv); 331 static void f_remote_send(typval_T *argvars, typval_T *rettv); 332 static void f_remote_startserver(typval_T *argvars, typval_T *rettv); 333 static void f_remove(typval_T *argvars, typval_T *rettv); 334 static void f_rename(typval_T *argvars, typval_T *rettv); 335 static void f_repeat(typval_T *argvars, typval_T *rettv); 336 static void f_resolve(typval_T *argvars, typval_T *rettv); 337 static void f_reverse(typval_T *argvars, typval_T *rettv); 338 #ifdef FEAT_FLOAT 339 static void f_round(typval_T *argvars, typval_T *rettv); 340 #endif 341 static void f_screenattr(typval_T *argvars, typval_T *rettv); 342 static void f_screenchar(typval_T *argvars, typval_T *rettv); 343 static void f_screencol(typval_T *argvars, typval_T *rettv); 344 static void f_screenrow(typval_T *argvars, typval_T *rettv); 345 static void f_search(typval_T *argvars, typval_T *rettv); 346 static void f_searchdecl(typval_T *argvars, typval_T *rettv); 347 static void f_searchpair(typval_T *argvars, typval_T *rettv); 348 static void f_searchpairpos(typval_T *argvars, typval_T *rettv); 349 static void f_searchpos(typval_T *argvars, typval_T *rettv); 350 static void f_server2client(typval_T *argvars, typval_T *rettv); 351 static void f_serverlist(typval_T *argvars, typval_T *rettv); 352 static void f_setbufline(typval_T *argvars, typval_T *rettv); 353 static void f_setbufvar(typval_T *argvars, typval_T *rettv); 354 static void f_setcharsearch(typval_T *argvars, typval_T *rettv); 355 static void f_setcmdpos(typval_T *argvars, typval_T *rettv); 356 static void f_setfperm(typval_T *argvars, typval_T *rettv); 357 static void f_setline(typval_T *argvars, typval_T *rettv); 358 static void f_setloclist(typval_T *argvars, typval_T *rettv); 359 static void f_setmatches(typval_T *argvars, typval_T *rettv); 360 static void f_setpos(typval_T *argvars, typval_T *rettv); 361 static void f_setqflist(typval_T *argvars, typval_T *rettv); 362 static void f_setreg(typval_T *argvars, typval_T *rettv); 363 static void f_settabvar(typval_T *argvars, typval_T *rettv); 364 static void f_settabwinvar(typval_T *argvars, typval_T *rettv); 365 static void f_settagstack(typval_T *argvars, typval_T *rettv); 366 static void f_setwinvar(typval_T *argvars, typval_T *rettv); 367 #ifdef FEAT_CRYPT 368 static void f_sha256(typval_T *argvars, typval_T *rettv); 369 #endif /* FEAT_CRYPT */ 370 static void f_shellescape(typval_T *argvars, typval_T *rettv); 371 static void f_shiftwidth(typval_T *argvars, typval_T *rettv); 372 #ifdef FEAT_SIGNS 373 static void f_sign_define(typval_T *argvars, typval_T *rettv); 374 static void f_sign_getdefined(typval_T *argvars, typval_T *rettv); 375 static void f_sign_getplaced(typval_T *argvars, typval_T *rettv); 376 static void f_sign_jump(typval_T *argvars, typval_T *rettv); 377 static void f_sign_place(typval_T *argvars, typval_T *rettv); 378 static void f_sign_undefine(typval_T *argvars, typval_T *rettv); 379 static void f_sign_unplace(typval_T *argvars, typval_T *rettv); 380 #endif 381 static void f_simplify(typval_T *argvars, typval_T *rettv); 382 #ifdef FEAT_FLOAT 383 static void f_sin(typval_T *argvars, typval_T *rettv); 384 static void f_sinh(typval_T *argvars, typval_T *rettv); 385 #endif 386 static void f_sort(typval_T *argvars, typval_T *rettv); 387 static void f_soundfold(typval_T *argvars, typval_T *rettv); 388 static void f_spellbadword(typval_T *argvars, typval_T *rettv); 389 static void f_spellsuggest(typval_T *argvars, typval_T *rettv); 390 static void f_split(typval_T *argvars, typval_T *rettv); 391 #ifdef FEAT_FLOAT 392 static void f_sqrt(typval_T *argvars, typval_T *rettv); 393 static void f_str2float(typval_T *argvars, typval_T *rettv); 394 #endif 395 static void f_str2nr(typval_T *argvars, typval_T *rettv); 396 static void f_strchars(typval_T *argvars, typval_T *rettv); 397 #ifdef HAVE_STRFTIME 398 static void f_strftime(typval_T *argvars, typval_T *rettv); 399 #endif 400 static void f_strgetchar(typval_T *argvars, typval_T *rettv); 401 static void f_stridx(typval_T *argvars, typval_T *rettv); 402 static void f_strlen(typval_T *argvars, typval_T *rettv); 403 static void f_strcharpart(typval_T *argvars, typval_T *rettv); 404 static void f_strpart(typval_T *argvars, typval_T *rettv); 405 static void f_strridx(typval_T *argvars, typval_T *rettv); 406 static void f_strtrans(typval_T *argvars, typval_T *rettv); 407 static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv); 408 static void f_strwidth(typval_T *argvars, typval_T *rettv); 409 static void f_submatch(typval_T *argvars, typval_T *rettv); 410 static void f_substitute(typval_T *argvars, typval_T *rettv); 411 static void f_swapinfo(typval_T *argvars, typval_T *rettv); 412 static void f_swapname(typval_T *argvars, typval_T *rettv); 413 static void f_synID(typval_T *argvars, typval_T *rettv); 414 static void f_synIDattr(typval_T *argvars, typval_T *rettv); 415 static void f_synIDtrans(typval_T *argvars, typval_T *rettv); 416 static void f_synstack(typval_T *argvars, typval_T *rettv); 417 static void f_synconcealed(typval_T *argvars, typval_T *rettv); 418 static void f_system(typval_T *argvars, typval_T *rettv); 419 static void f_systemlist(typval_T *argvars, typval_T *rettv); 420 static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv); 421 static void f_tabpagenr(typval_T *argvars, typval_T *rettv); 422 static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv); 423 static void f_taglist(typval_T *argvars, typval_T *rettv); 424 static void f_tagfiles(typval_T *argvars, typval_T *rettv); 425 static void f_tempname(typval_T *argvars, typval_T *rettv); 426 static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv); 427 static void f_test_autochdir(typval_T *argvars, typval_T *rettv); 428 static void f_test_feedinput(typval_T *argvars, typval_T *rettv); 429 static void f_test_option_not_set(typval_T *argvars, typval_T *rettv); 430 static void f_test_override(typval_T *argvars, typval_T *rettv); 431 static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv); 432 static void f_test_ignore_error(typval_T *argvars, typval_T *rettv); 433 static void f_test_null_blob(typval_T *argvars, typval_T *rettv); 434 #ifdef FEAT_JOB_CHANNEL 435 static void f_test_null_channel(typval_T *argvars, typval_T *rettv); 436 #endif 437 static void f_test_null_dict(typval_T *argvars, typval_T *rettv); 438 #ifdef FEAT_JOB_CHANNEL 439 static void f_test_null_job(typval_T *argvars, typval_T *rettv); 440 #endif 441 static void f_test_null_list(typval_T *argvars, typval_T *rettv); 442 static void f_test_null_partial(typval_T *argvars, typval_T *rettv); 443 static void f_test_null_string(typval_T *argvars, typval_T *rettv); 444 #ifdef FEAT_GUI 445 static void f_test_scrollbar(typval_T *argvars, typval_T *rettv); 446 #endif 447 static void f_test_settime(typval_T *argvars, typval_T *rettv); 448 #ifdef FEAT_FLOAT 449 static void f_tan(typval_T *argvars, typval_T *rettv); 450 static void f_tanh(typval_T *argvars, typval_T *rettv); 451 #endif 452 #ifdef FEAT_TIMERS 453 static void f_timer_info(typval_T *argvars, typval_T *rettv); 454 static void f_timer_pause(typval_T *argvars, typval_T *rettv); 455 static void f_timer_start(typval_T *argvars, typval_T *rettv); 456 static void f_timer_stop(typval_T *argvars, typval_T *rettv); 457 static void f_timer_stopall(typval_T *argvars, typval_T *rettv); 458 #endif 459 static void f_tolower(typval_T *argvars, typval_T *rettv); 460 static void f_toupper(typval_T *argvars, typval_T *rettv); 461 static void f_tr(typval_T *argvars, typval_T *rettv); 462 static void f_trim(typval_T *argvars, typval_T *rettv); 463 #ifdef FEAT_FLOAT 464 static void f_trunc(typval_T *argvars, typval_T *rettv); 465 #endif 466 static void f_type(typval_T *argvars, typval_T *rettv); 467 static void f_undofile(typval_T *argvars, typval_T *rettv); 468 static void f_undotree(typval_T *argvars, typval_T *rettv); 469 static void f_uniq(typval_T *argvars, typval_T *rettv); 470 static void f_values(typval_T *argvars, typval_T *rettv); 471 static void f_virtcol(typval_T *argvars, typval_T *rettv); 472 static void f_visualmode(typval_T *argvars, typval_T *rettv); 473 static void f_wildmenumode(typval_T *argvars, typval_T *rettv); 474 static void f_win_findbuf(typval_T *argvars, typval_T *rettv); 475 static void f_win_getid(typval_T *argvars, typval_T *rettv); 476 static void f_win_gotoid(typval_T *argvars, typval_T *rettv); 477 static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv); 478 static void f_win_id2win(typval_T *argvars, typval_T *rettv); 479 static void f_win_screenpos(typval_T *argvars, typval_T *rettv); 480 static void f_winbufnr(typval_T *argvars, typval_T *rettv); 481 static void f_wincol(typval_T *argvars, typval_T *rettv); 482 static void f_winheight(typval_T *argvars, typval_T *rettv); 483 static void f_winlayout(typval_T *argvars, typval_T *rettv); 484 static void f_winline(typval_T *argvars, typval_T *rettv); 485 static void f_winnr(typval_T *argvars, typval_T *rettv); 486 static void f_winrestcmd(typval_T *argvars, typval_T *rettv); 487 static void f_winrestview(typval_T *argvars, typval_T *rettv); 488 static void f_winsaveview(typval_T *argvars, typval_T *rettv); 489 static void f_winwidth(typval_T *argvars, typval_T *rettv); 490 static void f_writefile(typval_T *argvars, typval_T *rettv); 491 static void f_wordcount(typval_T *argvars, typval_T *rettv); 492 static void f_xor(typval_T *argvars, typval_T *rettv); 493 494 /* 495 * Array with names and number of arguments of all internal functions 496 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH! 497 */ 498 static struct fst 499 { 500 char *f_name; /* function name */ 501 char f_min_argc; /* minimal number of arguments */ 502 char f_max_argc; /* maximal number of arguments */ 503 void (*f_func)(typval_T *args, typval_T *rvar); 504 /* implementation of function */ 505 } functions[] = 506 { 507 #ifdef FEAT_FLOAT 508 {"abs", 1, 1, f_abs}, 509 {"acos", 1, 1, f_acos}, /* WJMc */ 510 #endif 511 {"add", 2, 2, f_add}, 512 {"and", 2, 2, f_and}, 513 {"append", 2, 2, f_append}, 514 {"appendbufline", 3, 3, f_appendbufline}, 515 {"argc", 0, 1, f_argc}, 516 {"argidx", 0, 0, f_argidx}, 517 {"arglistid", 0, 2, f_arglistid}, 518 {"argv", 0, 2, f_argv}, 519 #ifdef FEAT_FLOAT 520 {"asin", 1, 1, f_asin}, /* WJMc */ 521 #endif 522 {"assert_beeps", 1, 2, f_assert_beeps}, 523 {"assert_equal", 2, 3, f_assert_equal}, 524 {"assert_equalfile", 2, 2, f_assert_equalfile}, 525 {"assert_exception", 1, 2, f_assert_exception}, 526 {"assert_fails", 1, 3, f_assert_fails}, 527 {"assert_false", 1, 2, f_assert_false}, 528 {"assert_inrange", 3, 4, f_assert_inrange}, 529 {"assert_match", 2, 3, f_assert_match}, 530 {"assert_notequal", 2, 3, f_assert_notequal}, 531 {"assert_notmatch", 2, 3, f_assert_notmatch}, 532 {"assert_report", 1, 1, f_assert_report}, 533 {"assert_true", 1, 2, f_assert_true}, 534 #ifdef FEAT_FLOAT 535 {"atan", 1, 1, f_atan}, 536 {"atan2", 2, 2, f_atan2}, 537 #endif 538 #ifdef FEAT_BEVAL 539 {"balloon_show", 1, 1, f_balloon_show}, 540 # if defined(FEAT_BEVAL_TERM) 541 {"balloon_split", 1, 1, f_balloon_split}, 542 # endif 543 #endif 544 {"browse", 4, 4, f_browse}, 545 {"browsedir", 2, 2, f_browsedir}, 546 {"bufexists", 1, 1, f_bufexists}, 547 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */ 548 {"buffer_name", 1, 1, f_bufname}, /* obsolete */ 549 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */ 550 {"buflisted", 1, 1, f_buflisted}, 551 {"bufloaded", 1, 1, f_bufloaded}, 552 {"bufname", 1, 1, f_bufname}, 553 {"bufnr", 1, 2, f_bufnr}, 554 {"bufwinid", 1, 1, f_bufwinid}, 555 {"bufwinnr", 1, 1, f_bufwinnr}, 556 {"byte2line", 1, 1, f_byte2line}, 557 {"byteidx", 2, 2, f_byteidx}, 558 {"byteidxcomp", 2, 2, f_byteidxcomp}, 559 {"call", 2, 3, f_call}, 560 #ifdef FEAT_FLOAT 561 {"ceil", 1, 1, f_ceil}, 562 #endif 563 #ifdef FEAT_JOB_CHANNEL 564 {"ch_canread", 1, 1, f_ch_canread}, 565 {"ch_close", 1, 1, f_ch_close}, 566 {"ch_close_in", 1, 1, f_ch_close_in}, 567 {"ch_evalexpr", 2, 3, f_ch_evalexpr}, 568 {"ch_evalraw", 2, 3, f_ch_evalraw}, 569 {"ch_getbufnr", 2, 2, f_ch_getbufnr}, 570 {"ch_getjob", 1, 1, f_ch_getjob}, 571 {"ch_info", 1, 1, f_ch_info}, 572 {"ch_log", 1, 2, f_ch_log}, 573 {"ch_logfile", 1, 2, f_ch_logfile}, 574 {"ch_open", 1, 2, f_ch_open}, 575 {"ch_read", 1, 2, f_ch_read}, 576 {"ch_readblob", 1, 2, f_ch_readblob}, 577 {"ch_readraw", 1, 2, f_ch_readraw}, 578 {"ch_sendexpr", 2, 3, f_ch_sendexpr}, 579 {"ch_sendraw", 2, 3, f_ch_sendraw}, 580 {"ch_setoptions", 2, 2, f_ch_setoptions}, 581 {"ch_status", 1, 2, f_ch_status}, 582 #endif 583 {"changenr", 0, 0, f_changenr}, 584 {"char2nr", 1, 2, f_char2nr}, 585 {"cindent", 1, 1, f_cindent}, 586 {"clearmatches", 0, 0, f_clearmatches}, 587 {"col", 1, 1, f_col}, 588 #if defined(FEAT_INS_EXPAND) 589 {"complete", 2, 2, f_complete}, 590 {"complete_add", 1, 1, f_complete_add}, 591 {"complete_check", 0, 0, f_complete_check}, 592 #endif 593 {"confirm", 1, 4, f_confirm}, 594 {"copy", 1, 1, f_copy}, 595 #ifdef FEAT_FLOAT 596 {"cos", 1, 1, f_cos}, 597 {"cosh", 1, 1, f_cosh}, 598 #endif 599 {"count", 2, 4, f_count}, 600 {"cscope_connection",0,3, f_cscope_connection}, 601 {"cursor", 1, 3, f_cursor}, 602 #ifdef WIN3264 603 {"debugbreak", 1, 1, f_debugbreak}, 604 #endif 605 {"deepcopy", 1, 2, f_deepcopy}, 606 {"delete", 1, 2, f_delete}, 607 {"deletebufline", 2, 3, f_deletebufline}, 608 {"did_filetype", 0, 0, f_did_filetype}, 609 {"diff_filler", 1, 1, f_diff_filler}, 610 {"diff_hlID", 2, 2, f_diff_hlID}, 611 {"empty", 1, 1, f_empty}, 612 {"escape", 2, 2, f_escape}, 613 {"eval", 1, 1, f_eval}, 614 {"eventhandler", 0, 0, f_eventhandler}, 615 {"executable", 1, 1, f_executable}, 616 {"execute", 1, 2, f_execute}, 617 {"exepath", 1, 1, f_exepath}, 618 {"exists", 1, 1, f_exists}, 619 #ifdef FEAT_FLOAT 620 {"exp", 1, 1, f_exp}, 621 #endif 622 {"expand", 1, 3, f_expand}, 623 {"extend", 2, 3, f_extend}, 624 {"feedkeys", 1, 2, f_feedkeys}, 625 {"file_readable", 1, 1, f_filereadable}, /* obsolete */ 626 {"filereadable", 1, 1, f_filereadable}, 627 {"filewritable", 1, 1, f_filewritable}, 628 {"filter", 2, 2, f_filter}, 629 {"finddir", 1, 3, f_finddir}, 630 {"findfile", 1, 3, f_findfile}, 631 #ifdef FEAT_FLOAT 632 {"float2nr", 1, 1, f_float2nr}, 633 {"floor", 1, 1, f_floor}, 634 {"fmod", 2, 2, f_fmod}, 635 #endif 636 {"fnameescape", 1, 1, f_fnameescape}, 637 {"fnamemodify", 2, 2, f_fnamemodify}, 638 {"foldclosed", 1, 1, f_foldclosed}, 639 {"foldclosedend", 1, 1, f_foldclosedend}, 640 {"foldlevel", 1, 1, f_foldlevel}, 641 {"foldtext", 0, 0, f_foldtext}, 642 {"foldtextresult", 1, 1, f_foldtextresult}, 643 {"foreground", 0, 0, f_foreground}, 644 {"funcref", 1, 3, f_funcref}, 645 {"function", 1, 3, f_function}, 646 {"garbagecollect", 0, 1, f_garbagecollect}, 647 {"get", 2, 3, f_get}, 648 {"getbufinfo", 0, 1, f_getbufinfo}, 649 {"getbufline", 2, 3, f_getbufline}, 650 {"getbufvar", 2, 3, f_getbufvar}, 651 {"getchangelist", 1, 1, f_getchangelist}, 652 {"getchar", 0, 1, f_getchar}, 653 {"getcharmod", 0, 0, f_getcharmod}, 654 {"getcharsearch", 0, 0, f_getcharsearch}, 655 {"getcmdline", 0, 0, f_getcmdline}, 656 {"getcmdpos", 0, 0, f_getcmdpos}, 657 {"getcmdtype", 0, 0, f_getcmdtype}, 658 {"getcmdwintype", 0, 0, f_getcmdwintype}, 659 #if defined(FEAT_CMDL_COMPL) 660 {"getcompletion", 2, 3, f_getcompletion}, 661 #endif 662 {"getcurpos", 0, 0, f_getcurpos}, 663 {"getcwd", 0, 2, f_getcwd}, 664 {"getfontname", 0, 1, f_getfontname}, 665 {"getfperm", 1, 1, f_getfperm}, 666 {"getfsize", 1, 1, f_getfsize}, 667 {"getftime", 1, 1, f_getftime}, 668 {"getftype", 1, 1, f_getftype}, 669 {"getjumplist", 0, 2, f_getjumplist}, 670 {"getline", 1, 2, f_getline}, 671 {"getloclist", 1, 2, f_getloclist}, 672 {"getmatches", 0, 0, f_getmatches}, 673 {"getpid", 0, 0, f_getpid}, 674 {"getpos", 1, 1, f_getpos}, 675 {"getqflist", 0, 1, f_getqflist}, 676 {"getreg", 0, 3, f_getreg}, 677 {"getregtype", 0, 1, f_getregtype}, 678 {"gettabinfo", 0, 1, f_gettabinfo}, 679 {"gettabvar", 2, 3, f_gettabvar}, 680 {"gettabwinvar", 3, 4, f_gettabwinvar}, 681 {"gettagstack", 0, 1, f_gettagstack}, 682 {"getwininfo", 0, 1, f_getwininfo}, 683 {"getwinpos", 0, 1, f_getwinpos}, 684 {"getwinposx", 0, 0, f_getwinposx}, 685 {"getwinposy", 0, 0, f_getwinposy}, 686 {"getwinvar", 2, 3, f_getwinvar}, 687 {"glob", 1, 4, f_glob}, 688 {"glob2regpat", 1, 1, f_glob2regpat}, 689 {"globpath", 2, 5, f_globpath}, 690 {"has", 1, 1, f_has}, 691 {"has_key", 2, 2, f_has_key}, 692 {"haslocaldir", 0, 2, f_haslocaldir}, 693 {"hasmapto", 1, 3, f_hasmapto}, 694 {"highlightID", 1, 1, f_hlID}, /* obsolete */ 695 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */ 696 {"histadd", 2, 2, f_histadd}, 697 {"histdel", 1, 2, f_histdel}, 698 {"histget", 1, 2, f_histget}, 699 {"histnr", 1, 1, f_histnr}, 700 {"hlID", 1, 1, f_hlID}, 701 {"hlexists", 1, 1, f_hlexists}, 702 {"hostname", 0, 0, f_hostname}, 703 {"iconv", 3, 3, f_iconv}, 704 {"indent", 1, 1, f_indent}, 705 {"index", 2, 4, f_index}, 706 {"input", 1, 3, f_input}, 707 {"inputdialog", 1, 3, f_inputdialog}, 708 {"inputlist", 1, 1, f_inputlist}, 709 {"inputrestore", 0, 0, f_inputrestore}, 710 {"inputsave", 0, 0, f_inputsave}, 711 {"inputsecret", 1, 2, f_inputsecret}, 712 {"insert", 2, 3, f_insert}, 713 {"invert", 1, 1, f_invert}, 714 {"isdirectory", 1, 1, f_isdirectory}, 715 {"islocked", 1, 1, f_islocked}, 716 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) 717 {"isnan", 1, 1, f_isnan}, 718 #endif 719 {"items", 1, 1, f_items}, 720 #ifdef FEAT_JOB_CHANNEL 721 {"job_getchannel", 1, 1, f_job_getchannel}, 722 {"job_info", 0, 1, f_job_info}, 723 {"job_setoptions", 2, 2, f_job_setoptions}, 724 {"job_start", 1, 2, f_job_start}, 725 {"job_status", 1, 1, f_job_status}, 726 {"job_stop", 1, 2, f_job_stop}, 727 #endif 728 {"join", 1, 2, f_join}, 729 {"js_decode", 1, 1, f_js_decode}, 730 {"js_encode", 1, 1, f_js_encode}, 731 {"json_decode", 1, 1, f_json_decode}, 732 {"json_encode", 1, 1, f_json_encode}, 733 {"keys", 1, 1, f_keys}, 734 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */ 735 {"len", 1, 1, f_len}, 736 {"libcall", 3, 3, f_libcall}, 737 {"libcallnr", 3, 3, f_libcallnr}, 738 {"line", 1, 1, f_line}, 739 {"line2byte", 1, 1, f_line2byte}, 740 {"lispindent", 1, 1, f_lispindent}, 741 {"localtime", 0, 0, f_localtime}, 742 #ifdef FEAT_FLOAT 743 {"log", 1, 1, f_log}, 744 {"log10", 1, 1, f_log10}, 745 #endif 746 #ifdef FEAT_LUA 747 {"luaeval", 1, 2, f_luaeval}, 748 #endif 749 {"map", 2, 2, f_map}, 750 {"maparg", 1, 4, f_maparg}, 751 {"mapcheck", 1, 3, f_mapcheck}, 752 {"match", 2, 4, f_match}, 753 {"matchadd", 2, 5, f_matchadd}, 754 {"matchaddpos", 2, 5, f_matchaddpos}, 755 {"matcharg", 1, 1, f_matcharg}, 756 {"matchdelete", 1, 1, f_matchdelete}, 757 {"matchend", 2, 4, f_matchend}, 758 {"matchlist", 2, 4, f_matchlist}, 759 {"matchstr", 2, 4, f_matchstr}, 760 {"matchstrpos", 2, 4, f_matchstrpos}, 761 {"max", 1, 1, f_max}, 762 {"min", 1, 1, f_min}, 763 #ifdef vim_mkdir 764 {"mkdir", 1, 3, f_mkdir}, 765 #endif 766 {"mode", 0, 1, f_mode}, 767 #ifdef FEAT_MZSCHEME 768 {"mzeval", 1, 1, f_mzeval}, 769 #endif 770 {"nextnonblank", 1, 1, f_nextnonblank}, 771 {"nr2char", 1, 2, f_nr2char}, 772 {"or", 2, 2, f_or}, 773 {"pathshorten", 1, 1, f_pathshorten}, 774 #ifdef FEAT_PERL 775 {"perleval", 1, 1, f_perleval}, 776 #endif 777 #ifdef FEAT_FLOAT 778 {"pow", 2, 2, f_pow}, 779 #endif 780 {"prevnonblank", 1, 1, f_prevnonblank}, 781 {"printf", 1, 19, f_printf}, 782 #ifdef FEAT_JOB_CHANNEL 783 {"prompt_setcallback", 2, 2, f_prompt_setcallback}, 784 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt}, 785 {"prompt_setprompt", 2, 2, f_prompt_setprompt}, 786 #endif 787 #ifdef FEAT_TEXT_PROP 788 {"prop_add", 3, 3, f_prop_add}, 789 {"prop_clear", 1, 3, f_prop_clear}, 790 {"prop_list", 1, 2, f_prop_list}, 791 {"prop_remove", 2, 3, f_prop_remove}, 792 {"prop_type_add", 2, 2, f_prop_type_add}, 793 {"prop_type_change", 2, 2, f_prop_type_change}, 794 {"prop_type_delete", 1, 2, f_prop_type_delete}, 795 {"prop_type_get", 1, 2, f_prop_type_get}, 796 {"prop_type_list", 0, 1, f_prop_type_list}, 797 #endif 798 {"pumvisible", 0, 0, f_pumvisible}, 799 #ifdef FEAT_PYTHON3 800 {"py3eval", 1, 1, f_py3eval}, 801 #endif 802 #ifdef FEAT_PYTHON 803 {"pyeval", 1, 1, f_pyeval}, 804 #endif 805 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) 806 {"pyxeval", 1, 1, f_pyxeval}, 807 #endif 808 {"range", 1, 3, f_range}, 809 {"readfile", 1, 3, f_readfile}, 810 {"reg_executing", 0, 0, f_reg_executing}, 811 {"reg_recording", 0, 0, f_reg_recording}, 812 {"reltime", 0, 2, f_reltime}, 813 #ifdef FEAT_FLOAT 814 {"reltimefloat", 1, 1, f_reltimefloat}, 815 #endif 816 {"reltimestr", 1, 1, f_reltimestr}, 817 {"remote_expr", 2, 4, f_remote_expr}, 818 {"remote_foreground", 1, 1, f_remote_foreground}, 819 {"remote_peek", 1, 2, f_remote_peek}, 820 {"remote_read", 1, 2, f_remote_read}, 821 {"remote_send", 2, 3, f_remote_send}, 822 {"remote_startserver", 1, 1, f_remote_startserver}, 823 {"remove", 2, 3, f_remove}, 824 {"rename", 2, 2, f_rename}, 825 {"repeat", 2, 2, f_repeat}, 826 {"resolve", 1, 1, f_resolve}, 827 {"reverse", 1, 1, f_reverse}, 828 #ifdef FEAT_FLOAT 829 {"round", 1, 1, f_round}, 830 #endif 831 {"screenattr", 2, 2, f_screenattr}, 832 {"screenchar", 2, 2, f_screenchar}, 833 {"screencol", 0, 0, f_screencol}, 834 {"screenrow", 0, 0, f_screenrow}, 835 {"search", 1, 4, f_search}, 836 {"searchdecl", 1, 3, f_searchdecl}, 837 {"searchpair", 3, 7, f_searchpair}, 838 {"searchpairpos", 3, 7, f_searchpairpos}, 839 {"searchpos", 1, 4, f_searchpos}, 840 {"server2client", 2, 2, f_server2client}, 841 {"serverlist", 0, 0, f_serverlist}, 842 {"setbufline", 3, 3, f_setbufline}, 843 {"setbufvar", 3, 3, f_setbufvar}, 844 {"setcharsearch", 1, 1, f_setcharsearch}, 845 {"setcmdpos", 1, 1, f_setcmdpos}, 846 {"setfperm", 2, 2, f_setfperm}, 847 {"setline", 2, 2, f_setline}, 848 {"setloclist", 2, 4, f_setloclist}, 849 {"setmatches", 1, 1, f_setmatches}, 850 {"setpos", 2, 2, f_setpos}, 851 {"setqflist", 1, 3, f_setqflist}, 852 {"setreg", 2, 3, f_setreg}, 853 {"settabvar", 3, 3, f_settabvar}, 854 {"settabwinvar", 4, 4, f_settabwinvar}, 855 {"settagstack", 2, 3, f_settagstack}, 856 {"setwinvar", 3, 3, f_setwinvar}, 857 #ifdef FEAT_CRYPT 858 {"sha256", 1, 1, f_sha256}, 859 #endif 860 {"shellescape", 1, 2, f_shellescape}, 861 {"shiftwidth", 0, 1, f_shiftwidth}, 862 #ifdef FEAT_SIGNS 863 {"sign_define", 1, 2, f_sign_define}, 864 {"sign_getdefined", 0, 1, f_sign_getdefined}, 865 {"sign_getplaced", 0, 2, f_sign_getplaced}, 866 {"sign_jump", 3, 3, f_sign_jump}, 867 {"sign_place", 4, 5, f_sign_place}, 868 {"sign_undefine", 0, 1, f_sign_undefine}, 869 {"sign_unplace", 1, 2, f_sign_unplace}, 870 #endif 871 {"simplify", 1, 1, f_simplify}, 872 #ifdef FEAT_FLOAT 873 {"sin", 1, 1, f_sin}, 874 {"sinh", 1, 1, f_sinh}, 875 #endif 876 {"sort", 1, 3, f_sort}, 877 {"soundfold", 1, 1, f_soundfold}, 878 {"spellbadword", 0, 1, f_spellbadword}, 879 {"spellsuggest", 1, 3, f_spellsuggest}, 880 {"split", 1, 3, f_split}, 881 #ifdef FEAT_FLOAT 882 {"sqrt", 1, 1, f_sqrt}, 883 {"str2float", 1, 1, f_str2float}, 884 #endif 885 {"str2nr", 1, 2, f_str2nr}, 886 {"strcharpart", 2, 3, f_strcharpart}, 887 {"strchars", 1, 2, f_strchars}, 888 {"strdisplaywidth", 1, 2, f_strdisplaywidth}, 889 #ifdef HAVE_STRFTIME 890 {"strftime", 1, 2, f_strftime}, 891 #endif 892 {"strgetchar", 2, 2, f_strgetchar}, 893 {"stridx", 2, 3, f_stridx}, 894 {"string", 1, 1, f_string}, 895 {"strlen", 1, 1, f_strlen}, 896 {"strpart", 2, 3, f_strpart}, 897 {"strridx", 2, 3, f_strridx}, 898 {"strtrans", 1, 1, f_strtrans}, 899 {"strwidth", 1, 1, f_strwidth}, 900 {"submatch", 1, 2, f_submatch}, 901 {"substitute", 4, 4, f_substitute}, 902 {"swapinfo", 1, 1, f_swapinfo}, 903 {"swapname", 1, 1, f_swapname}, 904 {"synID", 3, 3, f_synID}, 905 {"synIDattr", 2, 3, f_synIDattr}, 906 {"synIDtrans", 1, 1, f_synIDtrans}, 907 {"synconcealed", 2, 2, f_synconcealed}, 908 {"synstack", 2, 2, f_synstack}, 909 {"system", 1, 2, f_system}, 910 {"systemlist", 1, 2, f_systemlist}, 911 {"tabpagebuflist", 0, 1, f_tabpagebuflist}, 912 {"tabpagenr", 0, 1, f_tabpagenr}, 913 {"tabpagewinnr", 1, 2, f_tabpagewinnr}, 914 {"tagfiles", 0, 0, f_tagfiles}, 915 {"taglist", 1, 2, f_taglist}, 916 #ifdef FEAT_FLOAT 917 {"tan", 1, 1, f_tan}, 918 {"tanh", 1, 1, f_tanh}, 919 #endif 920 {"tempname", 0, 0, f_tempname}, 921 #ifdef FEAT_TERMINAL 922 {"term_dumpdiff", 2, 3, f_term_dumpdiff}, 923 {"term_dumpload", 1, 2, f_term_dumpload}, 924 {"term_dumpwrite", 2, 3, f_term_dumpwrite}, 925 {"term_getaltscreen", 1, 1, f_term_getaltscreen}, 926 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 927 {"term_getansicolors", 1, 1, f_term_getansicolors}, 928 # endif 929 {"term_getattr", 2, 2, f_term_getattr}, 930 {"term_getcursor", 1, 1, f_term_getcursor}, 931 {"term_getjob", 1, 1, f_term_getjob}, 932 {"term_getline", 2, 2, f_term_getline}, 933 {"term_getscrolled", 1, 1, f_term_getscrolled}, 934 {"term_getsize", 1, 1, f_term_getsize}, 935 {"term_getstatus", 1, 1, f_term_getstatus}, 936 {"term_gettitle", 1, 1, f_term_gettitle}, 937 {"term_gettty", 1, 2, f_term_gettty}, 938 {"term_list", 0, 0, f_term_list}, 939 {"term_scrape", 2, 2, f_term_scrape}, 940 {"term_sendkeys", 2, 2, f_term_sendkeys}, 941 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 942 {"term_setansicolors", 2, 2, f_term_setansicolors}, 943 # endif 944 {"term_setkill", 2, 2, f_term_setkill}, 945 {"term_setrestore", 2, 2, f_term_setrestore}, 946 {"term_setsize", 3, 3, f_term_setsize}, 947 {"term_start", 1, 2, f_term_start}, 948 {"term_wait", 1, 2, f_term_wait}, 949 #endif 950 {"test_alloc_fail", 3, 3, f_test_alloc_fail}, 951 {"test_autochdir", 0, 0, f_test_autochdir}, 952 {"test_feedinput", 1, 1, f_test_feedinput}, 953 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now}, 954 {"test_ignore_error", 1, 1, f_test_ignore_error}, 955 {"test_null_blob", 0, 0, f_test_null_blob}, 956 #ifdef FEAT_JOB_CHANNEL 957 {"test_null_channel", 0, 0, f_test_null_channel}, 958 #endif 959 {"test_null_dict", 0, 0, f_test_null_dict}, 960 #ifdef FEAT_JOB_CHANNEL 961 {"test_null_job", 0, 0, f_test_null_job}, 962 #endif 963 {"test_null_list", 0, 0, f_test_null_list}, 964 {"test_null_partial", 0, 0, f_test_null_partial}, 965 {"test_null_string", 0, 0, f_test_null_string}, 966 {"test_option_not_set", 1, 1, f_test_option_not_set}, 967 {"test_override", 2, 2, f_test_override}, 968 #ifdef FEAT_GUI 969 {"test_scrollbar", 3, 3, f_test_scrollbar}, 970 #endif 971 {"test_settime", 1, 1, f_test_settime}, 972 #ifdef FEAT_TIMERS 973 {"timer_info", 0, 1, f_timer_info}, 974 {"timer_pause", 2, 2, f_timer_pause}, 975 {"timer_start", 2, 3, f_timer_start}, 976 {"timer_stop", 1, 1, f_timer_stop}, 977 {"timer_stopall", 0, 0, f_timer_stopall}, 978 #endif 979 {"tolower", 1, 1, f_tolower}, 980 {"toupper", 1, 1, f_toupper}, 981 {"tr", 3, 3, f_tr}, 982 {"trim", 1, 2, f_trim}, 983 #ifdef FEAT_FLOAT 984 {"trunc", 1, 1, f_trunc}, 985 #endif 986 {"type", 1, 1, f_type}, 987 {"undofile", 1, 1, f_undofile}, 988 {"undotree", 0, 0, f_undotree}, 989 {"uniq", 1, 3, f_uniq}, 990 {"values", 1, 1, f_values}, 991 {"virtcol", 1, 1, f_virtcol}, 992 {"visualmode", 0, 1, f_visualmode}, 993 {"wildmenumode", 0, 0, f_wildmenumode}, 994 {"win_findbuf", 1, 1, f_win_findbuf}, 995 {"win_getid", 0, 2, f_win_getid}, 996 {"win_gotoid", 1, 1, f_win_gotoid}, 997 {"win_id2tabwin", 1, 1, f_win_id2tabwin}, 998 {"win_id2win", 1, 1, f_win_id2win}, 999 {"win_screenpos", 1, 1, f_win_screenpos}, 1000 {"winbufnr", 1, 1, f_winbufnr}, 1001 {"wincol", 0, 0, f_wincol}, 1002 {"winheight", 1, 1, f_winheight}, 1003 {"winlayout", 0, 1, f_winlayout}, 1004 {"winline", 0, 0, f_winline}, 1005 {"winnr", 0, 1, f_winnr}, 1006 {"winrestcmd", 0, 0, f_winrestcmd}, 1007 {"winrestview", 1, 1, f_winrestview}, 1008 {"winsaveview", 0, 0, f_winsaveview}, 1009 {"winwidth", 1, 1, f_winwidth}, 1010 {"wordcount", 0, 0, f_wordcount}, 1011 {"writefile", 2, 3, f_writefile}, 1012 {"xor", 2, 2, f_xor}, 1013 }; 1014 1015 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 1016 1017 /* 1018 * Function given to ExpandGeneric() to obtain the list of internal 1019 * or user defined function names. 1020 */ 1021 char_u * 1022 get_function_name(expand_T *xp, int idx) 1023 { 1024 static int intidx = -1; 1025 char_u *name; 1026 1027 if (idx == 0) 1028 intidx = -1; 1029 if (intidx < 0) 1030 { 1031 name = get_user_func_name(xp, idx); 1032 if (name != NULL) 1033 return name; 1034 } 1035 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst))) 1036 { 1037 STRCPY(IObuff, functions[intidx].f_name); 1038 STRCAT(IObuff, "("); 1039 if (functions[intidx].f_max_argc == 0) 1040 STRCAT(IObuff, ")"); 1041 return IObuff; 1042 } 1043 1044 return NULL; 1045 } 1046 1047 /* 1048 * Function given to ExpandGeneric() to obtain the list of internal or 1049 * user defined variable or function names. 1050 */ 1051 char_u * 1052 get_expr_name(expand_T *xp, int idx) 1053 { 1054 static int intidx = -1; 1055 char_u *name; 1056 1057 if (idx == 0) 1058 intidx = -1; 1059 if (intidx < 0) 1060 { 1061 name = get_function_name(xp, idx); 1062 if (name != NULL) 1063 return name; 1064 } 1065 return get_user_var_name(xp, ++intidx); 1066 } 1067 1068 #endif /* FEAT_CMDL_COMPL */ 1069 1070 /* 1071 * Find internal function in table above. 1072 * Return index, or -1 if not found 1073 */ 1074 int 1075 find_internal_func( 1076 char_u *name) /* name of the function */ 1077 { 1078 int first = 0; 1079 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1; 1080 int cmp; 1081 int x; 1082 1083 /* 1084 * Find the function name in the table. Binary search. 1085 */ 1086 while (first <= last) 1087 { 1088 x = first + ((unsigned)(last - first) >> 1); 1089 cmp = STRCMP(name, functions[x].f_name); 1090 if (cmp < 0) 1091 last = x - 1; 1092 else if (cmp > 0) 1093 first = x + 1; 1094 else 1095 return x; 1096 } 1097 return -1; 1098 } 1099 1100 int 1101 call_internal_func( 1102 char_u *name, 1103 int argcount, 1104 typval_T *argvars, 1105 typval_T *rettv) 1106 { 1107 int i; 1108 1109 i = find_internal_func(name); 1110 if (i < 0) 1111 return ERROR_UNKNOWN; 1112 if (argcount < functions[i].f_min_argc) 1113 return ERROR_TOOFEW; 1114 if (argcount > functions[i].f_max_argc) 1115 return ERROR_TOOMANY; 1116 argvars[argcount].v_type = VAR_UNKNOWN; 1117 functions[i].f_func(argvars, rettv); 1118 return ERROR_NONE; 1119 } 1120 1121 /* 1122 * Return TRUE for a non-zero Number and a non-empty String. 1123 */ 1124 static int 1125 non_zero_arg(typval_T *argvars) 1126 { 1127 return ((argvars[0].v_type == VAR_NUMBER 1128 && argvars[0].vval.v_number != 0) 1129 || (argvars[0].v_type == VAR_SPECIAL 1130 && argvars[0].vval.v_number == VVAL_TRUE) 1131 || (argvars[0].v_type == VAR_STRING 1132 && argvars[0].vval.v_string != NULL 1133 && *argvars[0].vval.v_string != NUL)); 1134 } 1135 1136 /* 1137 * Get the lnum from the first argument. 1138 * Also accepts ".", "$", etc., but that only works for the current buffer. 1139 * Returns -1 on error. 1140 */ 1141 static linenr_T 1142 tv_get_lnum(typval_T *argvars) 1143 { 1144 typval_T rettv; 1145 linenr_T lnum; 1146 1147 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL); 1148 if (lnum == 0) /* no valid number, try using line() */ 1149 { 1150 rettv.v_type = VAR_NUMBER; 1151 f_line(argvars, &rettv); 1152 lnum = (linenr_T)rettv.vval.v_number; 1153 clear_tv(&rettv); 1154 } 1155 return lnum; 1156 } 1157 1158 /* 1159 * Get the lnum from the first argument. 1160 * Also accepts "$", then "buf" is used. 1161 * Returns 0 on error. 1162 */ 1163 static linenr_T 1164 tv_get_lnum_buf(typval_T *argvars, buf_T *buf) 1165 { 1166 if (argvars[0].v_type == VAR_STRING 1167 && argvars[0].vval.v_string != NULL 1168 && argvars[0].vval.v_string[0] == '$' 1169 && buf != NULL) 1170 return buf->b_ml.ml_line_count; 1171 return (linenr_T)tv_get_number_chk(&argvars[0], NULL); 1172 } 1173 1174 #ifdef FEAT_FLOAT 1175 /* 1176 * Get the float value of "argvars[0]" into "f". 1177 * Returns FAIL when the argument is not a Number or Float. 1178 */ 1179 static int 1180 get_float_arg(typval_T *argvars, float_T *f) 1181 { 1182 if (argvars[0].v_type == VAR_FLOAT) 1183 { 1184 *f = argvars[0].vval.v_float; 1185 return OK; 1186 } 1187 if (argvars[0].v_type == VAR_NUMBER) 1188 { 1189 *f = (float_T)argvars[0].vval.v_number; 1190 return OK; 1191 } 1192 emsg(_("E808: Number or Float required")); 1193 return FAIL; 1194 } 1195 1196 /* 1197 * "abs(expr)" function 1198 */ 1199 static void 1200 f_abs(typval_T *argvars, typval_T *rettv) 1201 { 1202 if (argvars[0].v_type == VAR_FLOAT) 1203 { 1204 rettv->v_type = VAR_FLOAT; 1205 rettv->vval.v_float = fabs(argvars[0].vval.v_float); 1206 } 1207 else 1208 { 1209 varnumber_T n; 1210 int error = FALSE; 1211 1212 n = tv_get_number_chk(&argvars[0], &error); 1213 if (error) 1214 rettv->vval.v_number = -1; 1215 else if (n > 0) 1216 rettv->vval.v_number = n; 1217 else 1218 rettv->vval.v_number = -n; 1219 } 1220 } 1221 1222 /* 1223 * "acos()" function 1224 */ 1225 static void 1226 f_acos(typval_T *argvars, typval_T *rettv) 1227 { 1228 float_T f = 0.0; 1229 1230 rettv->v_type = VAR_FLOAT; 1231 if (get_float_arg(argvars, &f) == OK) 1232 rettv->vval.v_float = acos(f); 1233 else 1234 rettv->vval.v_float = 0.0; 1235 } 1236 #endif 1237 1238 /* 1239 * "add(list, item)" function 1240 */ 1241 static void 1242 f_add(typval_T *argvars, typval_T *rettv) 1243 { 1244 list_T *l; 1245 blob_T *b; 1246 1247 rettv->vval.v_number = 1; /* Default: Failed */ 1248 if (argvars[0].v_type == VAR_LIST) 1249 { 1250 if ((l = argvars[0].vval.v_list) != NULL 1251 && !tv_check_lock(l->lv_lock, 1252 (char_u *)N_("add() argument"), TRUE) 1253 && list_append_tv(l, &argvars[1]) == OK) 1254 copy_tv(&argvars[0], rettv); 1255 } 1256 else if (argvars[0].v_type == VAR_BLOB) 1257 { 1258 if ((b = argvars[0].vval.v_blob) != NULL 1259 && !tv_check_lock(b->bv_lock, 1260 (char_u *)N_("add() argument"), TRUE)) 1261 { 1262 int error = FALSE; 1263 varnumber_T n = tv_get_number_chk(&argvars[1], &error); 1264 1265 if (!error) 1266 { 1267 ga_append(&b->bv_ga, (int)n); 1268 copy_tv(&argvars[0], rettv); 1269 } 1270 } 1271 } 1272 else 1273 emsg(_(e_listblobreq)); 1274 } 1275 1276 /* 1277 * "and(expr, expr)" function 1278 */ 1279 static void 1280 f_and(typval_T *argvars, typval_T *rettv) 1281 { 1282 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL) 1283 & tv_get_number_chk(&argvars[1], NULL); 1284 } 1285 1286 /* 1287 * If there is a window for "curbuf", make it the current window. 1288 */ 1289 static void 1290 find_win_for_curbuf(void) 1291 { 1292 wininfo_T *wip; 1293 1294 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next) 1295 { 1296 if (wip->wi_win != NULL) 1297 { 1298 curwin = wip->wi_win; 1299 break; 1300 } 1301 } 1302 } 1303 1304 /* 1305 * Set line or list of lines in buffer "buf". 1306 */ 1307 static void 1308 set_buffer_lines( 1309 buf_T *buf, 1310 linenr_T lnum_arg, 1311 int append, 1312 typval_T *lines, 1313 typval_T *rettv) 1314 { 1315 linenr_T lnum = lnum_arg + (append ? 1 : 0); 1316 char_u *line = NULL; 1317 list_T *l = NULL; 1318 listitem_T *li = NULL; 1319 long added = 0; 1320 linenr_T append_lnum; 1321 buf_T *curbuf_save = NULL; 1322 win_T *curwin_save = NULL; 1323 int is_curbuf = buf == curbuf; 1324 1325 /* When using the current buffer ml_mfp will be set if needed. Useful when 1326 * setline() is used on startup. For other buffers the buffer must be 1327 * loaded. */ 1328 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1) 1329 { 1330 rettv->vval.v_number = 1; /* FAIL */ 1331 return; 1332 } 1333 1334 if (!is_curbuf) 1335 { 1336 curbuf_save = curbuf; 1337 curwin_save = curwin; 1338 curbuf = buf; 1339 find_win_for_curbuf(); 1340 } 1341 1342 if (append) 1343 // appendbufline() uses the line number below which we insert 1344 append_lnum = lnum - 1; 1345 else 1346 // setbufline() uses the line number above which we insert, we only 1347 // append if it's below the last line 1348 append_lnum = curbuf->b_ml.ml_line_count; 1349 1350 if (lines->v_type == VAR_LIST) 1351 { 1352 l = lines->vval.v_list; 1353 li = l->lv_first; 1354 } 1355 else 1356 line = tv_get_string_chk(lines); 1357 1358 /* default result is zero == OK */ 1359 for (;;) 1360 { 1361 if (l != NULL) 1362 { 1363 /* list argument, get next string */ 1364 if (li == NULL) 1365 break; 1366 line = tv_get_string_chk(&li->li_tv); 1367 li = li->li_next; 1368 } 1369 1370 rettv->vval.v_number = 1; /* FAIL */ 1371 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1) 1372 break; 1373 1374 /* When coming here from Insert mode, sync undo, so that this can be 1375 * undone separately from what was previously inserted. */ 1376 if (u_sync_once == 2) 1377 { 1378 u_sync_once = 1; /* notify that u_sync() was called */ 1379 u_sync(TRUE); 1380 } 1381 1382 if (!append && lnum <= curbuf->b_ml.ml_line_count) 1383 { 1384 // Existing line, replace it. 1385 // Removes any existing text properties. 1386 if (u_savesub(lnum) == OK && ml_replace_len( 1387 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK) 1388 { 1389 changed_bytes(lnum, 0); 1390 if (is_curbuf && lnum == curwin->w_cursor.lnum) 1391 check_cursor_col(); 1392 rettv->vval.v_number = 0; /* OK */ 1393 } 1394 } 1395 else if (added > 0 || u_save(lnum - 1, lnum) == OK) 1396 { 1397 /* append the line */ 1398 ++added; 1399 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK) 1400 rettv->vval.v_number = 0; /* OK */ 1401 } 1402 1403 if (l == NULL) /* only one string argument */ 1404 break; 1405 ++lnum; 1406 } 1407 1408 if (added > 0) 1409 { 1410 win_T *wp; 1411 tabpage_T *tp; 1412 1413 appended_lines_mark(append_lnum, added); 1414 FOR_ALL_TAB_WINDOWS(tp, wp) 1415 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum) 1416 wp->w_cursor.lnum += added; 1417 check_cursor_col(); 1418 1419 #ifdef FEAT_JOB_CHANNEL 1420 if (bt_prompt(curbuf) && (State & INSERT)) 1421 // show the line with the prompt 1422 update_topline(); 1423 #endif 1424 } 1425 1426 if (!is_curbuf) 1427 { 1428 curbuf = curbuf_save; 1429 curwin = curwin_save; 1430 } 1431 } 1432 1433 /* 1434 * "append(lnum, string/list)" function 1435 */ 1436 static void 1437 f_append(typval_T *argvars, typval_T *rettv) 1438 { 1439 linenr_T lnum = tv_get_lnum(&argvars[0]); 1440 1441 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv); 1442 } 1443 1444 /* 1445 * "appendbufline(buf, lnum, string/list)" function 1446 */ 1447 static void 1448 f_appendbufline(typval_T *argvars, typval_T *rettv) 1449 { 1450 linenr_T lnum; 1451 buf_T *buf; 1452 1453 buf = tv_get_buf(&argvars[0], FALSE); 1454 if (buf == NULL) 1455 rettv->vval.v_number = 1; /* FAIL */ 1456 else 1457 { 1458 lnum = tv_get_lnum_buf(&argvars[1], buf); 1459 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv); 1460 } 1461 } 1462 1463 /* 1464 * "argc([window id])" function 1465 */ 1466 static void 1467 f_argc(typval_T *argvars, typval_T *rettv) 1468 { 1469 win_T *wp; 1470 1471 if (argvars[0].v_type == VAR_UNKNOWN) 1472 // use the current window 1473 rettv->vval.v_number = ARGCOUNT; 1474 else if (argvars[0].v_type == VAR_NUMBER 1475 && tv_get_number(&argvars[0]) == -1) 1476 // use the global argument list 1477 rettv->vval.v_number = GARGCOUNT; 1478 else 1479 { 1480 // use the argument list of the specified window 1481 wp = find_win_by_nr_or_id(&argvars[0]); 1482 if (wp != NULL) 1483 rettv->vval.v_number = WARGCOUNT(wp); 1484 else 1485 rettv->vval.v_number = -1; 1486 } 1487 } 1488 1489 /* 1490 * "argidx()" function 1491 */ 1492 static void 1493 f_argidx(typval_T *argvars UNUSED, typval_T *rettv) 1494 { 1495 rettv->vval.v_number = curwin->w_arg_idx; 1496 } 1497 1498 /* 1499 * "arglistid()" function 1500 */ 1501 static void 1502 f_arglistid(typval_T *argvars, typval_T *rettv) 1503 { 1504 win_T *wp; 1505 1506 rettv->vval.v_number = -1; 1507 wp = find_tabwin(&argvars[0], &argvars[1]); 1508 if (wp != NULL) 1509 rettv->vval.v_number = wp->w_alist->id; 1510 } 1511 1512 /* 1513 * Get the argument list for a given window 1514 */ 1515 static void 1516 get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv) 1517 { 1518 int idx; 1519 1520 if (rettv_list_alloc(rettv) == OK && arglist != NULL) 1521 for (idx = 0; idx < argcount; ++idx) 1522 list_append_string(rettv->vval.v_list, 1523 alist_name(&arglist[idx]), -1); 1524 } 1525 1526 /* 1527 * "argv(nr)" function 1528 */ 1529 static void 1530 f_argv(typval_T *argvars, typval_T *rettv) 1531 { 1532 int idx; 1533 aentry_T *arglist = NULL; 1534 int argcount = -1; 1535 1536 if (argvars[0].v_type != VAR_UNKNOWN) 1537 { 1538 if (argvars[1].v_type == VAR_UNKNOWN) 1539 { 1540 arglist = ARGLIST; 1541 argcount = ARGCOUNT; 1542 } 1543 else if (argvars[1].v_type == VAR_NUMBER 1544 && tv_get_number(&argvars[1]) == -1) 1545 { 1546 arglist = GARGLIST; 1547 argcount = GARGCOUNT; 1548 } 1549 else 1550 { 1551 win_T *wp = find_win_by_nr_or_id(&argvars[1]); 1552 1553 if (wp != NULL) 1554 { 1555 /* Use the argument list of the specified window */ 1556 arglist = WARGLIST(wp); 1557 argcount = WARGCOUNT(wp); 1558 } 1559 } 1560 1561 rettv->v_type = VAR_STRING; 1562 rettv->vval.v_string = NULL; 1563 idx = tv_get_number_chk(&argvars[0], NULL); 1564 if (arglist != NULL && idx >= 0 && idx < argcount) 1565 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx])); 1566 else if (idx == -1) 1567 get_arglist_as_rettv(arglist, argcount, rettv); 1568 } 1569 else 1570 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv); 1571 } 1572 1573 /* 1574 * "assert_beeps(cmd [, error])" function 1575 */ 1576 static void 1577 f_assert_beeps(typval_T *argvars, typval_T *rettv) 1578 { 1579 rettv->vval.v_number = assert_beeps(argvars); 1580 } 1581 1582 /* 1583 * "assert_equal(expected, actual[, msg])" function 1584 */ 1585 static void 1586 f_assert_equal(typval_T *argvars, typval_T *rettv) 1587 { 1588 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL); 1589 } 1590 1591 /* 1592 * "assert_equalfile(fname-one, fname-two)" function 1593 */ 1594 static void 1595 f_assert_equalfile(typval_T *argvars, typval_T *rettv) 1596 { 1597 rettv->vval.v_number = assert_equalfile(argvars); 1598 } 1599 1600 /* 1601 * "assert_notequal(expected, actual[, msg])" function 1602 */ 1603 static void 1604 f_assert_notequal(typval_T *argvars, typval_T *rettv) 1605 { 1606 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL); 1607 } 1608 1609 /* 1610 * "assert_exception(string[, msg])" function 1611 */ 1612 static void 1613 f_assert_exception(typval_T *argvars, typval_T *rettv) 1614 { 1615 rettv->vval.v_number = assert_exception(argvars); 1616 } 1617 1618 /* 1619 * "assert_fails(cmd [, error[, msg]])" function 1620 */ 1621 static void 1622 f_assert_fails(typval_T *argvars, typval_T *rettv) 1623 { 1624 rettv->vval.v_number = assert_fails(argvars); 1625 } 1626 1627 /* 1628 * "assert_false(actual[, msg])" function 1629 */ 1630 static void 1631 f_assert_false(typval_T *argvars, typval_T *rettv) 1632 { 1633 rettv->vval.v_number = assert_bool(argvars, FALSE); 1634 } 1635 1636 /* 1637 * "assert_inrange(lower, upper[, msg])" function 1638 */ 1639 static void 1640 f_assert_inrange(typval_T *argvars, typval_T *rettv) 1641 { 1642 rettv->vval.v_number = assert_inrange(argvars); 1643 } 1644 1645 /* 1646 * "assert_match(pattern, actual[, msg])" function 1647 */ 1648 static void 1649 f_assert_match(typval_T *argvars, typval_T *rettv) 1650 { 1651 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH); 1652 } 1653 1654 /* 1655 * "assert_notmatch(pattern, actual[, msg])" function 1656 */ 1657 static void 1658 f_assert_notmatch(typval_T *argvars, typval_T *rettv) 1659 { 1660 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH); 1661 } 1662 1663 /* 1664 * "assert_report(msg)" function 1665 */ 1666 static void 1667 f_assert_report(typval_T *argvars, typval_T *rettv) 1668 { 1669 rettv->vval.v_number = assert_report(argvars); 1670 } 1671 1672 /* 1673 * "assert_true(actual[, msg])" function 1674 */ 1675 static void 1676 f_assert_true(typval_T *argvars, typval_T *rettv) 1677 { 1678 rettv->vval.v_number = assert_bool(argvars, TRUE); 1679 } 1680 1681 #ifdef FEAT_FLOAT 1682 /* 1683 * "asin()" function 1684 */ 1685 static void 1686 f_asin(typval_T *argvars, typval_T *rettv) 1687 { 1688 float_T f = 0.0; 1689 1690 rettv->v_type = VAR_FLOAT; 1691 if (get_float_arg(argvars, &f) == OK) 1692 rettv->vval.v_float = asin(f); 1693 else 1694 rettv->vval.v_float = 0.0; 1695 } 1696 1697 /* 1698 * "atan()" function 1699 */ 1700 static void 1701 f_atan(typval_T *argvars, typval_T *rettv) 1702 { 1703 float_T f = 0.0; 1704 1705 rettv->v_type = VAR_FLOAT; 1706 if (get_float_arg(argvars, &f) == OK) 1707 rettv->vval.v_float = atan(f); 1708 else 1709 rettv->vval.v_float = 0.0; 1710 } 1711 1712 /* 1713 * "atan2()" function 1714 */ 1715 static void 1716 f_atan2(typval_T *argvars, typval_T *rettv) 1717 { 1718 float_T fx = 0.0, fy = 0.0; 1719 1720 rettv->v_type = VAR_FLOAT; 1721 if (get_float_arg(argvars, &fx) == OK 1722 && get_float_arg(&argvars[1], &fy) == OK) 1723 rettv->vval.v_float = atan2(fx, fy); 1724 else 1725 rettv->vval.v_float = 0.0; 1726 } 1727 #endif 1728 1729 /* 1730 * "balloon_show()" function 1731 */ 1732 #ifdef FEAT_BEVAL 1733 static void 1734 f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED) 1735 { 1736 if (balloonEval != NULL) 1737 { 1738 if (argvars[0].v_type == VAR_LIST 1739 # ifdef FEAT_GUI 1740 && !gui.in_use 1741 # endif 1742 ) 1743 post_balloon(balloonEval, NULL, argvars[0].vval.v_list); 1744 else 1745 post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL); 1746 } 1747 } 1748 1749 # if defined(FEAT_BEVAL_TERM) 1750 static void 1751 f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED) 1752 { 1753 if (rettv_list_alloc(rettv) == OK) 1754 { 1755 char_u *msg = tv_get_string_chk(&argvars[0]); 1756 1757 if (msg != NULL) 1758 { 1759 pumitem_T *array; 1760 int size = split_message(msg, &array); 1761 int i; 1762 1763 /* Skip the first and last item, they are always empty. */ 1764 for (i = 1; i < size - 1; ++i) 1765 list_append_string(rettv->vval.v_list, array[i].pum_text, -1); 1766 while (size > 0) 1767 vim_free(array[--size].pum_text); 1768 vim_free(array); 1769 } 1770 } 1771 } 1772 # endif 1773 #endif 1774 1775 /* 1776 * "browse(save, title, initdir, default)" function 1777 */ 1778 static void 1779 f_browse(typval_T *argvars UNUSED, typval_T *rettv) 1780 { 1781 #ifdef FEAT_BROWSE 1782 int save; 1783 char_u *title; 1784 char_u *initdir; 1785 char_u *defname; 1786 char_u buf[NUMBUFLEN]; 1787 char_u buf2[NUMBUFLEN]; 1788 int error = FALSE; 1789 1790 save = (int)tv_get_number_chk(&argvars[0], &error); 1791 title = tv_get_string_chk(&argvars[1]); 1792 initdir = tv_get_string_buf_chk(&argvars[2], buf); 1793 defname = tv_get_string_buf_chk(&argvars[3], buf2); 1794 1795 if (error || title == NULL || initdir == NULL || defname == NULL) 1796 rettv->vval.v_string = NULL; 1797 else 1798 rettv->vval.v_string = 1799 do_browse(save ? BROWSE_SAVE : 0, 1800 title, defname, NULL, initdir, NULL, curbuf); 1801 #else 1802 rettv->vval.v_string = NULL; 1803 #endif 1804 rettv->v_type = VAR_STRING; 1805 } 1806 1807 /* 1808 * "browsedir(title, initdir)" function 1809 */ 1810 static void 1811 f_browsedir(typval_T *argvars UNUSED, typval_T *rettv) 1812 { 1813 #ifdef FEAT_BROWSE 1814 char_u *title; 1815 char_u *initdir; 1816 char_u buf[NUMBUFLEN]; 1817 1818 title = tv_get_string_chk(&argvars[0]); 1819 initdir = tv_get_string_buf_chk(&argvars[1], buf); 1820 1821 if (title == NULL || initdir == NULL) 1822 rettv->vval.v_string = NULL; 1823 else 1824 rettv->vval.v_string = do_browse(BROWSE_DIR, 1825 title, NULL, NULL, initdir, NULL, curbuf); 1826 #else 1827 rettv->vval.v_string = NULL; 1828 #endif 1829 rettv->v_type = VAR_STRING; 1830 } 1831 1832 /* 1833 * Find a buffer by number or exact name. 1834 */ 1835 static buf_T * 1836 find_buffer(typval_T *avar) 1837 { 1838 buf_T *buf = NULL; 1839 1840 if (avar->v_type == VAR_NUMBER) 1841 buf = buflist_findnr((int)avar->vval.v_number); 1842 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) 1843 { 1844 buf = buflist_findname_exp(avar->vval.v_string); 1845 if (buf == NULL) 1846 { 1847 /* No full path name match, try a match with a URL or a "nofile" 1848 * buffer, these don't use the full path. */ 1849 FOR_ALL_BUFFERS(buf) 1850 if (buf->b_fname != NULL 1851 && (path_with_url(buf->b_fname) 1852 #ifdef FEAT_QUICKFIX 1853 || bt_nofile(buf) 1854 #endif 1855 ) 1856 && STRCMP(buf->b_fname, avar->vval.v_string) == 0) 1857 break; 1858 } 1859 } 1860 return buf; 1861 } 1862 1863 /* 1864 * "bufexists(expr)" function 1865 */ 1866 static void 1867 f_bufexists(typval_T *argvars, typval_T *rettv) 1868 { 1869 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL); 1870 } 1871 1872 /* 1873 * "buflisted(expr)" function 1874 */ 1875 static void 1876 f_buflisted(typval_T *argvars, typval_T *rettv) 1877 { 1878 buf_T *buf; 1879 1880 buf = find_buffer(&argvars[0]); 1881 rettv->vval.v_number = (buf != NULL && buf->b_p_bl); 1882 } 1883 1884 /* 1885 * "bufloaded(expr)" function 1886 */ 1887 static void 1888 f_bufloaded(typval_T *argvars, typval_T *rettv) 1889 { 1890 buf_T *buf; 1891 1892 buf = find_buffer(&argvars[0]); 1893 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL); 1894 } 1895 1896 buf_T * 1897 buflist_find_by_name(char_u *name, int curtab_only) 1898 { 1899 int save_magic; 1900 char_u *save_cpo; 1901 buf_T *buf; 1902 1903 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */ 1904 save_magic = p_magic; 1905 p_magic = TRUE; 1906 save_cpo = p_cpo; 1907 p_cpo = (char_u *)""; 1908 1909 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name), 1910 TRUE, FALSE, curtab_only)); 1911 1912 p_magic = save_magic; 1913 p_cpo = save_cpo; 1914 return buf; 1915 } 1916 1917 /* 1918 * Get buffer by number or pattern. 1919 */ 1920 buf_T * 1921 tv_get_buf(typval_T *tv, int curtab_only) 1922 { 1923 char_u *name = tv->vval.v_string; 1924 buf_T *buf; 1925 1926 if (tv->v_type == VAR_NUMBER) 1927 return buflist_findnr((int)tv->vval.v_number); 1928 if (tv->v_type != VAR_STRING) 1929 return NULL; 1930 if (name == NULL || *name == NUL) 1931 return curbuf; 1932 if (name[0] == '$' && name[1] == NUL) 1933 return lastbuf; 1934 1935 buf = buflist_find_by_name(name, curtab_only); 1936 1937 /* If not found, try expanding the name, like done for bufexists(). */ 1938 if (buf == NULL) 1939 buf = find_buffer(tv); 1940 1941 return buf; 1942 } 1943 1944 #ifdef FEAT_SIGNS 1945 /* 1946 * Get the buffer from "arg" and give an error and return NULL if it is not 1947 * valid. 1948 */ 1949 static buf_T * 1950 get_buf_arg(typval_T *arg) 1951 { 1952 buf_T *buf; 1953 1954 ++emsg_off; 1955 buf = tv_get_buf(arg, FALSE); 1956 --emsg_off; 1957 if (buf == NULL) 1958 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg)); 1959 return buf; 1960 } 1961 #endif 1962 1963 /* 1964 * "bufname(expr)" function 1965 */ 1966 static void 1967 f_bufname(typval_T *argvars, typval_T *rettv) 1968 { 1969 buf_T *buf; 1970 1971 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */ 1972 ++emsg_off; 1973 buf = tv_get_buf(&argvars[0], FALSE); 1974 rettv->v_type = VAR_STRING; 1975 if (buf != NULL && buf->b_fname != NULL) 1976 rettv->vval.v_string = vim_strsave(buf->b_fname); 1977 else 1978 rettv->vval.v_string = NULL; 1979 --emsg_off; 1980 } 1981 1982 /* 1983 * "bufnr(expr)" function 1984 */ 1985 static void 1986 f_bufnr(typval_T *argvars, typval_T *rettv) 1987 { 1988 buf_T *buf; 1989 int error = FALSE; 1990 char_u *name; 1991 1992 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */ 1993 ++emsg_off; 1994 buf = tv_get_buf(&argvars[0], FALSE); 1995 --emsg_off; 1996 1997 /* If the buffer isn't found and the second argument is not zero create a 1998 * new buffer. */ 1999 if (buf == NULL 2000 && argvars[1].v_type != VAR_UNKNOWN 2001 && tv_get_number_chk(&argvars[1], &error) != 0 2002 && !error 2003 && (name = tv_get_string_chk(&argvars[0])) != NULL 2004 && !error) 2005 buf = buflist_new(name, NULL, (linenr_T)1, 0); 2006 2007 if (buf != NULL) 2008 rettv->vval.v_number = buf->b_fnum; 2009 else 2010 rettv->vval.v_number = -1; 2011 } 2012 2013 static void 2014 buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr) 2015 { 2016 win_T *wp; 2017 int winnr = 0; 2018 buf_T *buf; 2019 2020 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */ 2021 ++emsg_off; 2022 buf = tv_get_buf(&argvars[0], TRUE); 2023 FOR_ALL_WINDOWS(wp) 2024 { 2025 ++winnr; 2026 if (wp->w_buffer == buf) 2027 break; 2028 } 2029 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1); 2030 --emsg_off; 2031 } 2032 2033 /* 2034 * "bufwinid(nr)" function 2035 */ 2036 static void 2037 f_bufwinid(typval_T *argvars, typval_T *rettv) 2038 { 2039 buf_win_common(argvars, rettv, FALSE); 2040 } 2041 2042 /* 2043 * "bufwinnr(nr)" function 2044 */ 2045 static void 2046 f_bufwinnr(typval_T *argvars, typval_T *rettv) 2047 { 2048 buf_win_common(argvars, rettv, TRUE); 2049 } 2050 2051 /* 2052 * "byte2line(byte)" function 2053 */ 2054 static void 2055 f_byte2line(typval_T *argvars UNUSED, typval_T *rettv) 2056 { 2057 #ifndef FEAT_BYTEOFF 2058 rettv->vval.v_number = -1; 2059 #else 2060 long boff = 0; 2061 2062 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */ 2063 if (boff < 0) 2064 rettv->vval.v_number = -1; 2065 else 2066 rettv->vval.v_number = ml_find_line_or_offset(curbuf, 2067 (linenr_T)0, &boff); 2068 #endif 2069 } 2070 2071 static void 2072 byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED) 2073 { 2074 char_u *t; 2075 char_u *str; 2076 varnumber_T idx; 2077 2078 str = tv_get_string_chk(&argvars[0]); 2079 idx = tv_get_number_chk(&argvars[1], NULL); 2080 rettv->vval.v_number = -1; 2081 if (str == NULL || idx < 0) 2082 return; 2083 2084 t = str; 2085 for ( ; idx > 0; idx--) 2086 { 2087 if (*t == NUL) /* EOL reached */ 2088 return; 2089 if (enc_utf8 && comp) 2090 t += utf_ptr2len(t); 2091 else 2092 t += (*mb_ptr2len)(t); 2093 } 2094 rettv->vval.v_number = (varnumber_T)(t - str); 2095 } 2096 2097 /* 2098 * "byteidx()" function 2099 */ 2100 static void 2101 f_byteidx(typval_T *argvars, typval_T *rettv) 2102 { 2103 byteidx(argvars, rettv, FALSE); 2104 } 2105 2106 /* 2107 * "byteidxcomp()" function 2108 */ 2109 static void 2110 f_byteidxcomp(typval_T *argvars, typval_T *rettv) 2111 { 2112 byteidx(argvars, rettv, TRUE); 2113 } 2114 2115 /* 2116 * "call(func, arglist [, dict])" function 2117 */ 2118 static void 2119 f_call(typval_T *argvars, typval_T *rettv) 2120 { 2121 char_u *func; 2122 partial_T *partial = NULL; 2123 dict_T *selfdict = NULL; 2124 2125 if (argvars[1].v_type != VAR_LIST) 2126 { 2127 emsg(_(e_listreq)); 2128 return; 2129 } 2130 if (argvars[1].vval.v_list == NULL) 2131 return; 2132 2133 if (argvars[0].v_type == VAR_FUNC) 2134 func = argvars[0].vval.v_string; 2135 else if (argvars[0].v_type == VAR_PARTIAL) 2136 { 2137 partial = argvars[0].vval.v_partial; 2138 func = partial_name(partial); 2139 } 2140 else 2141 func = tv_get_string(&argvars[0]); 2142 if (*func == NUL) 2143 return; /* type error or empty name */ 2144 2145 if (argvars[2].v_type != VAR_UNKNOWN) 2146 { 2147 if (argvars[2].v_type != VAR_DICT) 2148 { 2149 emsg(_(e_dictreq)); 2150 return; 2151 } 2152 selfdict = argvars[2].vval.v_dict; 2153 } 2154 2155 (void)func_call(func, &argvars[1], partial, selfdict, rettv); 2156 } 2157 2158 #ifdef FEAT_FLOAT 2159 /* 2160 * "ceil({float})" function 2161 */ 2162 static void 2163 f_ceil(typval_T *argvars, typval_T *rettv) 2164 { 2165 float_T f = 0.0; 2166 2167 rettv->v_type = VAR_FLOAT; 2168 if (get_float_arg(argvars, &f) == OK) 2169 rettv->vval.v_float = ceil(f); 2170 else 2171 rettv->vval.v_float = 0.0; 2172 } 2173 #endif 2174 2175 #ifdef FEAT_JOB_CHANNEL 2176 /* 2177 * "ch_canread()" function 2178 */ 2179 static void 2180 f_ch_canread(typval_T *argvars, typval_T *rettv) 2181 { 2182 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); 2183 2184 rettv->vval.v_number = 0; 2185 if (channel != NULL) 2186 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK) 2187 || channel_has_readahead(channel, PART_OUT) 2188 || channel_has_readahead(channel, PART_ERR); 2189 } 2190 2191 /* 2192 * "ch_close()" function 2193 */ 2194 static void 2195 f_ch_close(typval_T *argvars, typval_T *rettv UNUSED) 2196 { 2197 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); 2198 2199 if (channel != NULL) 2200 { 2201 channel_close(channel, FALSE); 2202 channel_clear(channel); 2203 } 2204 } 2205 2206 /* 2207 * "ch_close()" function 2208 */ 2209 static void 2210 f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED) 2211 { 2212 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); 2213 2214 if (channel != NULL) 2215 channel_close_in(channel); 2216 } 2217 2218 /* 2219 * "ch_getbufnr()" function 2220 */ 2221 static void 2222 f_ch_getbufnr(typval_T *argvars, typval_T *rettv) 2223 { 2224 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); 2225 2226 rettv->vval.v_number = -1; 2227 if (channel != NULL) 2228 { 2229 char_u *what = tv_get_string(&argvars[1]); 2230 int part; 2231 2232 if (STRCMP(what, "err") == 0) 2233 part = PART_ERR; 2234 else if (STRCMP(what, "out") == 0) 2235 part = PART_OUT; 2236 else if (STRCMP(what, "in") == 0) 2237 part = PART_IN; 2238 else 2239 part = PART_SOCK; 2240 if (channel->ch_part[part].ch_bufref.br_buf != NULL) 2241 rettv->vval.v_number = 2242 channel->ch_part[part].ch_bufref.br_buf->b_fnum; 2243 } 2244 } 2245 2246 /* 2247 * "ch_getjob()" function 2248 */ 2249 static void 2250 f_ch_getjob(typval_T *argvars, typval_T *rettv) 2251 { 2252 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); 2253 2254 if (channel != NULL) 2255 { 2256 rettv->v_type = VAR_JOB; 2257 rettv->vval.v_job = channel->ch_job; 2258 if (channel->ch_job != NULL) 2259 ++channel->ch_job->jv_refcount; 2260 } 2261 } 2262 2263 /* 2264 * "ch_info()" function 2265 */ 2266 static void 2267 f_ch_info(typval_T *argvars, typval_T *rettv UNUSED) 2268 { 2269 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); 2270 2271 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL) 2272 channel_info(channel, rettv->vval.v_dict); 2273 } 2274 2275 /* 2276 * "ch_log()" function 2277 */ 2278 static void 2279 f_ch_log(typval_T *argvars, typval_T *rettv UNUSED) 2280 { 2281 char_u *msg = tv_get_string(&argvars[0]); 2282 channel_T *channel = NULL; 2283 2284 if (argvars[1].v_type != VAR_UNKNOWN) 2285 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0); 2286 2287 ch_log(channel, "%s", msg); 2288 } 2289 2290 /* 2291 * "ch_logfile()" function 2292 */ 2293 static void 2294 f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED) 2295 { 2296 char_u *fname; 2297 char_u *opt = (char_u *)""; 2298 char_u buf[NUMBUFLEN]; 2299 2300 /* Don't open a file in restricted mode. */ 2301 if (check_restricted() || check_secure()) 2302 return; 2303 fname = tv_get_string(&argvars[0]); 2304 if (argvars[1].v_type == VAR_STRING) 2305 opt = tv_get_string_buf(&argvars[1], buf); 2306 ch_logfile(fname, opt); 2307 } 2308 2309 /* 2310 * "ch_open()" function 2311 */ 2312 static void 2313 f_ch_open(typval_T *argvars, typval_T *rettv) 2314 { 2315 rettv->v_type = VAR_CHANNEL; 2316 if (check_restricted() || check_secure()) 2317 return; 2318 rettv->vval.v_channel = channel_open_func(argvars); 2319 } 2320 2321 /* 2322 * "ch_read()" function 2323 */ 2324 static void 2325 f_ch_read(typval_T *argvars, typval_T *rettv) 2326 { 2327 common_channel_read(argvars, rettv, FALSE, FALSE); 2328 } 2329 2330 /* 2331 * "ch_readblob()" function 2332 */ 2333 static void 2334 f_ch_readblob(typval_T *argvars, typval_T *rettv) 2335 { 2336 common_channel_read(argvars, rettv, TRUE, TRUE); 2337 } 2338 2339 /* 2340 * "ch_readraw()" function 2341 */ 2342 static void 2343 f_ch_readraw(typval_T *argvars, typval_T *rettv) 2344 { 2345 common_channel_read(argvars, rettv, TRUE, FALSE); 2346 } 2347 2348 /* 2349 * "ch_evalexpr()" function 2350 */ 2351 static void 2352 f_ch_evalexpr(typval_T *argvars, typval_T *rettv) 2353 { 2354 ch_expr_common(argvars, rettv, TRUE); 2355 } 2356 2357 /* 2358 * "ch_sendexpr()" function 2359 */ 2360 static void 2361 f_ch_sendexpr(typval_T *argvars, typval_T *rettv) 2362 { 2363 ch_expr_common(argvars, rettv, FALSE); 2364 } 2365 2366 /* 2367 * "ch_evalraw()" function 2368 */ 2369 static void 2370 f_ch_evalraw(typval_T *argvars, typval_T *rettv) 2371 { 2372 ch_raw_common(argvars, rettv, TRUE); 2373 } 2374 2375 /* 2376 * "ch_sendraw()" function 2377 */ 2378 static void 2379 f_ch_sendraw(typval_T *argvars, typval_T *rettv) 2380 { 2381 ch_raw_common(argvars, rettv, FALSE); 2382 } 2383 2384 /* 2385 * "ch_setoptions()" function 2386 */ 2387 static void 2388 f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED) 2389 { 2390 channel_T *channel; 2391 jobopt_T opt; 2392 2393 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); 2394 if (channel == NULL) 2395 return; 2396 clear_job_options(&opt); 2397 if (get_job_options(&argvars[1], &opt, 2398 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK) 2399 channel_set_options(channel, &opt); 2400 free_job_options(&opt); 2401 } 2402 2403 /* 2404 * "ch_status()" function 2405 */ 2406 static void 2407 f_ch_status(typval_T *argvars, typval_T *rettv) 2408 { 2409 channel_T *channel; 2410 jobopt_T opt; 2411 int part = -1; 2412 2413 /* return an empty string by default */ 2414 rettv->v_type = VAR_STRING; 2415 rettv->vval.v_string = NULL; 2416 2417 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); 2418 2419 if (argvars[1].v_type != VAR_UNKNOWN) 2420 { 2421 clear_job_options(&opt); 2422 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK 2423 && (opt.jo_set & JO_PART)) 2424 part = opt.jo_part; 2425 } 2426 2427 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part)); 2428 } 2429 #endif 2430 2431 /* 2432 * "changenr()" function 2433 */ 2434 static void 2435 f_changenr(typval_T *argvars UNUSED, typval_T *rettv) 2436 { 2437 rettv->vval.v_number = curbuf->b_u_seq_cur; 2438 } 2439 2440 /* 2441 * "char2nr(string)" function 2442 */ 2443 static void 2444 f_char2nr(typval_T *argvars, typval_T *rettv) 2445 { 2446 if (has_mbyte) 2447 { 2448 int utf8 = 0; 2449 2450 if (argvars[1].v_type != VAR_UNKNOWN) 2451 utf8 = (int)tv_get_number_chk(&argvars[1], NULL); 2452 2453 if (utf8) 2454 rettv->vval.v_number = (*utf_ptr2char)(tv_get_string(&argvars[0])); 2455 else 2456 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0])); 2457 } 2458 else 2459 rettv->vval.v_number = tv_get_string(&argvars[0])[0]; 2460 } 2461 2462 /* 2463 * "cindent(lnum)" function 2464 */ 2465 static void 2466 f_cindent(typval_T *argvars UNUSED, typval_T *rettv) 2467 { 2468 #ifdef FEAT_CINDENT 2469 pos_T pos; 2470 linenr_T lnum; 2471 2472 pos = curwin->w_cursor; 2473 lnum = tv_get_lnum(argvars); 2474 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) 2475 { 2476 curwin->w_cursor.lnum = lnum; 2477 rettv->vval.v_number = get_c_indent(); 2478 curwin->w_cursor = pos; 2479 } 2480 else 2481 #endif 2482 rettv->vval.v_number = -1; 2483 } 2484 2485 /* 2486 * "clearmatches()" function 2487 */ 2488 static void 2489 f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 2490 { 2491 #ifdef FEAT_SEARCH_EXTRA 2492 clear_matches(curwin); 2493 #endif 2494 } 2495 2496 /* 2497 * "col(string)" function 2498 */ 2499 static void 2500 f_col(typval_T *argvars, typval_T *rettv) 2501 { 2502 colnr_T col = 0; 2503 pos_T *fp; 2504 int fnum = curbuf->b_fnum; 2505 2506 fp = var2fpos(&argvars[0], FALSE, &fnum); 2507 if (fp != NULL && fnum == curbuf->b_fnum) 2508 { 2509 if (fp->col == MAXCOL) 2510 { 2511 /* '> can be MAXCOL, get the length of the line then */ 2512 if (fp->lnum <= curbuf->b_ml.ml_line_count) 2513 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1; 2514 else 2515 col = MAXCOL; 2516 } 2517 else 2518 { 2519 col = fp->col + 1; 2520 /* col(".") when the cursor is on the NUL at the end of the line 2521 * because of "coladd" can be seen as an extra column. */ 2522 if (virtual_active() && fp == &curwin->w_cursor) 2523 { 2524 char_u *p = ml_get_cursor(); 2525 2526 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p, 2527 curwin->w_virtcol - curwin->w_cursor.coladd)) 2528 { 2529 int l; 2530 2531 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL) 2532 col += l; 2533 } 2534 } 2535 } 2536 } 2537 rettv->vval.v_number = col; 2538 } 2539 2540 #if defined(FEAT_INS_EXPAND) 2541 /* 2542 * "complete()" function 2543 */ 2544 static void 2545 f_complete(typval_T *argvars, typval_T *rettv UNUSED) 2546 { 2547 int startcol; 2548 2549 if ((State & INSERT) == 0) 2550 { 2551 emsg(_("E785: complete() can only be used in Insert mode")); 2552 return; 2553 } 2554 2555 /* Check for undo allowed here, because if something was already inserted 2556 * the line was already saved for undo and this check isn't done. */ 2557 if (!undo_allowed()) 2558 return; 2559 2560 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL) 2561 { 2562 emsg(_(e_invarg)); 2563 return; 2564 } 2565 2566 startcol = (int)tv_get_number_chk(&argvars[0], NULL); 2567 if (startcol <= 0) 2568 return; 2569 2570 set_completion(startcol - 1, argvars[1].vval.v_list); 2571 } 2572 2573 /* 2574 * "complete_add()" function 2575 */ 2576 static void 2577 f_complete_add(typval_T *argvars, typval_T *rettv) 2578 { 2579 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0); 2580 } 2581 2582 /* 2583 * "complete_check()" function 2584 */ 2585 static void 2586 f_complete_check(typval_T *argvars UNUSED, typval_T *rettv) 2587 { 2588 int saved = RedrawingDisabled; 2589 2590 RedrawingDisabled = 0; 2591 ins_compl_check_keys(0, TRUE); 2592 rettv->vval.v_number = compl_interrupted; 2593 RedrawingDisabled = saved; 2594 } 2595 #endif 2596 2597 /* 2598 * "confirm(message, buttons[, default [, type]])" function 2599 */ 2600 static void 2601 f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 2602 { 2603 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 2604 char_u *message; 2605 char_u *buttons = NULL; 2606 char_u buf[NUMBUFLEN]; 2607 char_u buf2[NUMBUFLEN]; 2608 int def = 1; 2609 int type = VIM_GENERIC; 2610 char_u *typestr; 2611 int error = FALSE; 2612 2613 message = tv_get_string_chk(&argvars[0]); 2614 if (message == NULL) 2615 error = TRUE; 2616 if (argvars[1].v_type != VAR_UNKNOWN) 2617 { 2618 buttons = tv_get_string_buf_chk(&argvars[1], buf); 2619 if (buttons == NULL) 2620 error = TRUE; 2621 if (argvars[2].v_type != VAR_UNKNOWN) 2622 { 2623 def = (int)tv_get_number_chk(&argvars[2], &error); 2624 if (argvars[3].v_type != VAR_UNKNOWN) 2625 { 2626 typestr = tv_get_string_buf_chk(&argvars[3], buf2); 2627 if (typestr == NULL) 2628 error = TRUE; 2629 else 2630 { 2631 switch (TOUPPER_ASC(*typestr)) 2632 { 2633 case 'E': type = VIM_ERROR; break; 2634 case 'Q': type = VIM_QUESTION; break; 2635 case 'I': type = VIM_INFO; break; 2636 case 'W': type = VIM_WARNING; break; 2637 case 'G': type = VIM_GENERIC; break; 2638 } 2639 } 2640 } 2641 } 2642 } 2643 2644 if (buttons == NULL || *buttons == NUL) 2645 buttons = (char_u *)_("&Ok"); 2646 2647 if (!error) 2648 rettv->vval.v_number = do_dialog(type, NULL, message, buttons, 2649 def, NULL, FALSE); 2650 #endif 2651 } 2652 2653 /* 2654 * "copy()" function 2655 */ 2656 static void 2657 f_copy(typval_T *argvars, typval_T *rettv) 2658 { 2659 item_copy(&argvars[0], rettv, FALSE, 0); 2660 } 2661 2662 #ifdef FEAT_FLOAT 2663 /* 2664 * "cos()" function 2665 */ 2666 static void 2667 f_cos(typval_T *argvars, typval_T *rettv) 2668 { 2669 float_T f = 0.0; 2670 2671 rettv->v_type = VAR_FLOAT; 2672 if (get_float_arg(argvars, &f) == OK) 2673 rettv->vval.v_float = cos(f); 2674 else 2675 rettv->vval.v_float = 0.0; 2676 } 2677 2678 /* 2679 * "cosh()" function 2680 */ 2681 static void 2682 f_cosh(typval_T *argvars, typval_T *rettv) 2683 { 2684 float_T f = 0.0; 2685 2686 rettv->v_type = VAR_FLOAT; 2687 if (get_float_arg(argvars, &f) == OK) 2688 rettv->vval.v_float = cosh(f); 2689 else 2690 rettv->vval.v_float = 0.0; 2691 } 2692 #endif 2693 2694 /* 2695 * "count()" function 2696 */ 2697 static void 2698 f_count(typval_T *argvars, typval_T *rettv) 2699 { 2700 long n = 0; 2701 int ic = FALSE; 2702 int error = FALSE; 2703 2704 if (argvars[2].v_type != VAR_UNKNOWN) 2705 ic = (int)tv_get_number_chk(&argvars[2], &error); 2706 2707 if (argvars[0].v_type == VAR_STRING) 2708 { 2709 char_u *expr = tv_get_string_chk(&argvars[1]); 2710 char_u *p = argvars[0].vval.v_string; 2711 char_u *next; 2712 2713 if (!error && expr != NULL && *expr != NUL && p != NULL) 2714 { 2715 if (ic) 2716 { 2717 size_t len = STRLEN(expr); 2718 2719 while (*p != NUL) 2720 { 2721 if (MB_STRNICMP(p, expr, len) == 0) 2722 { 2723 ++n; 2724 p += len; 2725 } 2726 else 2727 MB_PTR_ADV(p); 2728 } 2729 } 2730 else 2731 while ((next = (char_u *)strstr((char *)p, (char *)expr)) 2732 != NULL) 2733 { 2734 ++n; 2735 p = next + STRLEN(expr); 2736 } 2737 } 2738 2739 } 2740 else if (argvars[0].v_type == VAR_LIST) 2741 { 2742 listitem_T *li; 2743 list_T *l; 2744 long idx; 2745 2746 if ((l = argvars[0].vval.v_list) != NULL) 2747 { 2748 li = l->lv_first; 2749 if (argvars[2].v_type != VAR_UNKNOWN) 2750 { 2751 if (argvars[3].v_type != VAR_UNKNOWN) 2752 { 2753 idx = (long)tv_get_number_chk(&argvars[3], &error); 2754 if (!error) 2755 { 2756 li = list_find(l, idx); 2757 if (li == NULL) 2758 semsg(_(e_listidx), idx); 2759 } 2760 } 2761 if (error) 2762 li = NULL; 2763 } 2764 2765 for ( ; li != NULL; li = li->li_next) 2766 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE)) 2767 ++n; 2768 } 2769 } 2770 else if (argvars[0].v_type == VAR_DICT) 2771 { 2772 int todo; 2773 dict_T *d; 2774 hashitem_T *hi; 2775 2776 if ((d = argvars[0].vval.v_dict) != NULL) 2777 { 2778 if (argvars[2].v_type != VAR_UNKNOWN) 2779 { 2780 if (argvars[3].v_type != VAR_UNKNOWN) 2781 emsg(_(e_invarg)); 2782 } 2783 2784 todo = error ? 0 : (int)d->dv_hashtab.ht_used; 2785 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) 2786 { 2787 if (!HASHITEM_EMPTY(hi)) 2788 { 2789 --todo; 2790 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE)) 2791 ++n; 2792 } 2793 } 2794 } 2795 } 2796 else 2797 semsg(_(e_listdictarg), "count()"); 2798 rettv->vval.v_number = n; 2799 } 2800 2801 /* 2802 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function 2803 * 2804 * Checks the existence of a cscope connection. 2805 */ 2806 static void 2807 f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 2808 { 2809 #ifdef FEAT_CSCOPE 2810 int num = 0; 2811 char_u *dbpath = NULL; 2812 char_u *prepend = NULL; 2813 char_u buf[NUMBUFLEN]; 2814 2815 if (argvars[0].v_type != VAR_UNKNOWN 2816 && argvars[1].v_type != VAR_UNKNOWN) 2817 { 2818 num = (int)tv_get_number(&argvars[0]); 2819 dbpath = tv_get_string(&argvars[1]); 2820 if (argvars[2].v_type != VAR_UNKNOWN) 2821 prepend = tv_get_string_buf(&argvars[2], buf); 2822 } 2823 2824 rettv->vval.v_number = cs_connection(num, dbpath, prepend); 2825 #endif 2826 } 2827 2828 /* 2829 * "cursor(lnum, col)" function, or 2830 * "cursor(list)" 2831 * 2832 * Moves the cursor to the specified line and column. 2833 * Returns 0 when the position could be set, -1 otherwise. 2834 */ 2835 static void 2836 f_cursor(typval_T *argvars, typval_T *rettv) 2837 { 2838 long line, col; 2839 long coladd = 0; 2840 int set_curswant = TRUE; 2841 2842 rettv->vval.v_number = -1; 2843 if (argvars[1].v_type == VAR_UNKNOWN) 2844 { 2845 pos_T pos; 2846 colnr_T curswant = -1; 2847 2848 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL) 2849 { 2850 emsg(_(e_invarg)); 2851 return; 2852 } 2853 line = pos.lnum; 2854 col = pos.col; 2855 coladd = pos.coladd; 2856 if (curswant >= 0) 2857 { 2858 curwin->w_curswant = curswant - 1; 2859 set_curswant = FALSE; 2860 } 2861 } 2862 else 2863 { 2864 line = tv_get_lnum(argvars); 2865 col = (long)tv_get_number_chk(&argvars[1], NULL); 2866 if (argvars[2].v_type != VAR_UNKNOWN) 2867 coladd = (long)tv_get_number_chk(&argvars[2], NULL); 2868 } 2869 if (line < 0 || col < 0 || coladd < 0) 2870 return; /* type error; errmsg already given */ 2871 if (line > 0) 2872 curwin->w_cursor.lnum = line; 2873 if (col > 0) 2874 curwin->w_cursor.col = col - 1; 2875 curwin->w_cursor.coladd = coladd; 2876 2877 /* Make sure the cursor is in a valid position. */ 2878 check_cursor(); 2879 /* Correct cursor for multi-byte character. */ 2880 if (has_mbyte) 2881 mb_adjust_cursor(); 2882 2883 curwin->w_set_curswant = set_curswant; 2884 rettv->vval.v_number = 0; 2885 } 2886 2887 #ifdef WIN3264 2888 /* 2889 * "debugbreak()" function 2890 */ 2891 static void 2892 f_debugbreak(typval_T *argvars, typval_T *rettv) 2893 { 2894 int pid; 2895 2896 rettv->vval.v_number = FAIL; 2897 pid = (int)tv_get_number(&argvars[0]); 2898 if (pid == 0) 2899 emsg(_(e_invarg)); 2900 else 2901 { 2902 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid); 2903 2904 if (hProcess != NULL) 2905 { 2906 DebugBreakProcess(hProcess); 2907 CloseHandle(hProcess); 2908 rettv->vval.v_number = OK; 2909 } 2910 } 2911 } 2912 #endif 2913 2914 /* 2915 * "deepcopy()" function 2916 */ 2917 static void 2918 f_deepcopy(typval_T *argvars, typval_T *rettv) 2919 { 2920 int noref = 0; 2921 int copyID; 2922 2923 if (argvars[1].v_type != VAR_UNKNOWN) 2924 noref = (int)tv_get_number_chk(&argvars[1], NULL); 2925 if (noref < 0 || noref > 1) 2926 emsg(_(e_invarg)); 2927 else 2928 { 2929 copyID = get_copyID(); 2930 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0); 2931 } 2932 } 2933 2934 /* 2935 * "delete()" function 2936 */ 2937 static void 2938 f_delete(typval_T *argvars, typval_T *rettv) 2939 { 2940 char_u nbuf[NUMBUFLEN]; 2941 char_u *name; 2942 char_u *flags; 2943 2944 rettv->vval.v_number = -1; 2945 if (check_restricted() || check_secure()) 2946 return; 2947 2948 name = tv_get_string(&argvars[0]); 2949 if (name == NULL || *name == NUL) 2950 { 2951 emsg(_(e_invarg)); 2952 return; 2953 } 2954 2955 if (argvars[1].v_type != VAR_UNKNOWN) 2956 flags = tv_get_string_buf(&argvars[1], nbuf); 2957 else 2958 flags = (char_u *)""; 2959 2960 if (*flags == NUL) 2961 /* delete a file */ 2962 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1; 2963 else if (STRCMP(flags, "d") == 0) 2964 /* delete an empty directory */ 2965 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1; 2966 else if (STRCMP(flags, "rf") == 0) 2967 /* delete a directory recursively */ 2968 rettv->vval.v_number = delete_recursive(name); 2969 else 2970 semsg(_(e_invexpr2), flags); 2971 } 2972 2973 /* 2974 * "deletebufline()" function 2975 */ 2976 static void 2977 f_deletebufline(typval_T *argvars, typval_T *rettv) 2978 { 2979 buf_T *buf; 2980 linenr_T first, last; 2981 linenr_T lnum; 2982 long count; 2983 int is_curbuf; 2984 buf_T *curbuf_save = NULL; 2985 win_T *curwin_save = NULL; 2986 tabpage_T *tp; 2987 win_T *wp; 2988 2989 buf = tv_get_buf(&argvars[0], FALSE); 2990 if (buf == NULL) 2991 { 2992 rettv->vval.v_number = 1; /* FAIL */ 2993 return; 2994 } 2995 is_curbuf = buf == curbuf; 2996 2997 first = tv_get_lnum_buf(&argvars[1], buf); 2998 if (argvars[2].v_type != VAR_UNKNOWN) 2999 last = tv_get_lnum_buf(&argvars[2], buf); 3000 else 3001 last = first; 3002 3003 if (buf->b_ml.ml_mfp == NULL || first < 1 3004 || first > buf->b_ml.ml_line_count || last < first) 3005 { 3006 rettv->vval.v_number = 1; /* FAIL */ 3007 return; 3008 } 3009 3010 if (!is_curbuf) 3011 { 3012 curbuf_save = curbuf; 3013 curwin_save = curwin; 3014 curbuf = buf; 3015 find_win_for_curbuf(); 3016 } 3017 if (last > curbuf->b_ml.ml_line_count) 3018 last = curbuf->b_ml.ml_line_count; 3019 count = last - first + 1; 3020 3021 // When coming here from Insert mode, sync undo, so that this can be 3022 // undone separately from what was previously inserted. 3023 if (u_sync_once == 2) 3024 { 3025 u_sync_once = 1; // notify that u_sync() was called 3026 u_sync(TRUE); 3027 } 3028 3029 if (u_save(first - 1, last + 1) == FAIL) 3030 { 3031 rettv->vval.v_number = 1; /* FAIL */ 3032 return; 3033 } 3034 3035 for (lnum = first; lnum <= last; ++lnum) 3036 ml_delete(first, TRUE); 3037 3038 FOR_ALL_TAB_WINDOWS(tp, wp) 3039 if (wp->w_buffer == buf) 3040 { 3041 if (wp->w_cursor.lnum > last) 3042 wp->w_cursor.lnum -= count; 3043 else if (wp->w_cursor.lnum> first) 3044 wp->w_cursor.lnum = first; 3045 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) 3046 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count; 3047 } 3048 check_cursor_col(); 3049 deleted_lines_mark(first, count); 3050 3051 if (!is_curbuf) 3052 { 3053 curbuf = curbuf_save; 3054 curwin = curwin_save; 3055 } 3056 } 3057 3058 /* 3059 * "did_filetype()" function 3060 */ 3061 static void 3062 f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 3063 { 3064 rettv->vval.v_number = did_filetype; 3065 } 3066 3067 /* 3068 * "diff_filler()" function 3069 */ 3070 static void 3071 f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 3072 { 3073 #ifdef FEAT_DIFF 3074 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars)); 3075 #endif 3076 } 3077 3078 /* 3079 * "diff_hlID()" function 3080 */ 3081 static void 3082 f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 3083 { 3084 #ifdef FEAT_DIFF 3085 linenr_T lnum = tv_get_lnum(argvars); 3086 static linenr_T prev_lnum = 0; 3087 static varnumber_T changedtick = 0; 3088 static int fnum = 0; 3089 static int change_start = 0; 3090 static int change_end = 0; 3091 static hlf_T hlID = (hlf_T)0; 3092 int filler_lines; 3093 int col; 3094 3095 if (lnum < 0) /* ignore type error in {lnum} arg */ 3096 lnum = 0; 3097 if (lnum != prev_lnum 3098 || changedtick != CHANGEDTICK(curbuf) 3099 || fnum != curbuf->b_fnum) 3100 { 3101 /* New line, buffer, change: need to get the values. */ 3102 filler_lines = diff_check(curwin, lnum); 3103 if (filler_lines < 0) 3104 { 3105 if (filler_lines == -1) 3106 { 3107 change_start = MAXCOL; 3108 change_end = -1; 3109 if (diff_find_change(curwin, lnum, &change_start, &change_end)) 3110 hlID = HLF_ADD; /* added line */ 3111 else 3112 hlID = HLF_CHD; /* changed line */ 3113 } 3114 else 3115 hlID = HLF_ADD; /* added line */ 3116 } 3117 else 3118 hlID = (hlf_T)0; 3119 prev_lnum = lnum; 3120 changedtick = CHANGEDTICK(curbuf); 3121 fnum = curbuf->b_fnum; 3122 } 3123 3124 if (hlID == HLF_CHD || hlID == HLF_TXD) 3125 { 3126 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */ 3127 if (col >= change_start && col <= change_end) 3128 hlID = HLF_TXD; /* changed text */ 3129 else 3130 hlID = HLF_CHD; /* changed line */ 3131 } 3132 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID; 3133 #endif 3134 } 3135 3136 /* 3137 * "empty({expr})" function 3138 */ 3139 static void 3140 f_empty(typval_T *argvars, typval_T *rettv) 3141 { 3142 int n = FALSE; 3143 3144 switch (argvars[0].v_type) 3145 { 3146 case VAR_STRING: 3147 case VAR_FUNC: 3148 n = argvars[0].vval.v_string == NULL 3149 || *argvars[0].vval.v_string == NUL; 3150 break; 3151 case VAR_PARTIAL: 3152 n = FALSE; 3153 break; 3154 case VAR_NUMBER: 3155 n = argvars[0].vval.v_number == 0; 3156 break; 3157 case VAR_FLOAT: 3158 #ifdef FEAT_FLOAT 3159 n = argvars[0].vval.v_float == 0.0; 3160 break; 3161 #endif 3162 case VAR_LIST: 3163 n = argvars[0].vval.v_list == NULL 3164 || argvars[0].vval.v_list->lv_first == NULL; 3165 break; 3166 case VAR_DICT: 3167 n = argvars[0].vval.v_dict == NULL 3168 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0; 3169 break; 3170 case VAR_SPECIAL: 3171 n = argvars[0].vval.v_number != VVAL_TRUE; 3172 break; 3173 3174 case VAR_BLOB: 3175 n = argvars[0].vval.v_blob == NULL 3176 || argvars[0].vval.v_blob->bv_ga.ga_len == 0; 3177 break; 3178 3179 case VAR_JOB: 3180 #ifdef FEAT_JOB_CHANNEL 3181 n = argvars[0].vval.v_job == NULL 3182 || argvars[0].vval.v_job->jv_status != JOB_STARTED; 3183 break; 3184 #endif 3185 case VAR_CHANNEL: 3186 #ifdef FEAT_JOB_CHANNEL 3187 n = argvars[0].vval.v_channel == NULL 3188 || !channel_is_open(argvars[0].vval.v_channel); 3189 break; 3190 #endif 3191 case VAR_UNKNOWN: 3192 internal_error("f_empty(UNKNOWN)"); 3193 n = TRUE; 3194 break; 3195 } 3196 3197 rettv->vval.v_number = n; 3198 } 3199 3200 /* 3201 * "escape({string}, {chars})" function 3202 */ 3203 static void 3204 f_escape(typval_T *argvars, typval_T *rettv) 3205 { 3206 char_u buf[NUMBUFLEN]; 3207 3208 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]), 3209 tv_get_string_buf(&argvars[1], buf)); 3210 rettv->v_type = VAR_STRING; 3211 } 3212 3213 /* 3214 * "eval()" function 3215 */ 3216 static void 3217 f_eval(typval_T *argvars, typval_T *rettv) 3218 { 3219 char_u *s, *p; 3220 3221 s = tv_get_string_chk(&argvars[0]); 3222 if (s != NULL) 3223 s = skipwhite(s); 3224 3225 p = s; 3226 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL) 3227 { 3228 if (p != NULL && !aborting()) 3229 semsg(_(e_invexpr2), p); 3230 need_clr_eos = FALSE; 3231 rettv->v_type = VAR_NUMBER; 3232 rettv->vval.v_number = 0; 3233 } 3234 else if (*s != NUL) 3235 emsg(_(e_trailing)); 3236 } 3237 3238 /* 3239 * "eventhandler()" function 3240 */ 3241 static void 3242 f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv) 3243 { 3244 rettv->vval.v_number = vgetc_busy; 3245 } 3246 3247 /* 3248 * "executable()" function 3249 */ 3250 static void 3251 f_executable(typval_T *argvars, typval_T *rettv) 3252 { 3253 char_u *name = tv_get_string(&argvars[0]); 3254 3255 /* Check in $PATH and also check directly if there is a directory name. */ 3256 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE) 3257 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE)); 3258 } 3259 3260 static garray_T redir_execute_ga; 3261 3262 /* 3263 * Append "value[value_len]" to the execute() output. 3264 */ 3265 void 3266 execute_redir_str(char_u *value, int value_len) 3267 { 3268 int len; 3269 3270 if (value_len == -1) 3271 len = (int)STRLEN(value); /* Append the entire string */ 3272 else 3273 len = value_len; /* Append only "value_len" characters */ 3274 if (ga_grow(&redir_execute_ga, len) == OK) 3275 { 3276 mch_memmove((char *)redir_execute_ga.ga_data 3277 + redir_execute_ga.ga_len, value, len); 3278 redir_execute_ga.ga_len += len; 3279 } 3280 } 3281 3282 /* 3283 * Get next line from a list. 3284 * Called by do_cmdline() to get the next line. 3285 * Returns allocated string, or NULL for end of function. 3286 */ 3287 3288 static char_u * 3289 get_list_line( 3290 int c UNUSED, 3291 void *cookie, 3292 int indent UNUSED) 3293 { 3294 listitem_T **p = (listitem_T **)cookie; 3295 listitem_T *item = *p; 3296 char_u buf[NUMBUFLEN]; 3297 char_u *s; 3298 3299 if (item == NULL) 3300 return NULL; 3301 s = tv_get_string_buf_chk(&item->li_tv, buf); 3302 *p = item->li_next; 3303 return s == NULL ? NULL : vim_strsave(s); 3304 } 3305 3306 /* 3307 * "execute()" function 3308 */ 3309 static void 3310 f_execute(typval_T *argvars, typval_T *rettv) 3311 { 3312 char_u *cmd = NULL; 3313 list_T *list = NULL; 3314 int save_msg_silent = msg_silent; 3315 int save_emsg_silent = emsg_silent; 3316 int save_emsg_noredir = emsg_noredir; 3317 int save_redir_execute = redir_execute; 3318 int save_redir_off = redir_off; 3319 garray_T save_ga; 3320 int save_msg_col = msg_col; 3321 int echo_output = FALSE; 3322 3323 rettv->vval.v_string = NULL; 3324 rettv->v_type = VAR_STRING; 3325 3326 if (argvars[0].v_type == VAR_LIST) 3327 { 3328 list = argvars[0].vval.v_list; 3329 if (list == NULL || list->lv_first == NULL) 3330 /* empty list, no commands, empty output */ 3331 return; 3332 ++list->lv_refcount; 3333 } 3334 else 3335 { 3336 cmd = tv_get_string_chk(&argvars[0]); 3337 if (cmd == NULL) 3338 return; 3339 } 3340 3341 if (argvars[1].v_type != VAR_UNKNOWN) 3342 { 3343 char_u buf[NUMBUFLEN]; 3344 char_u *s = tv_get_string_buf_chk(&argvars[1], buf); 3345 3346 if (s == NULL) 3347 return; 3348 if (*s == NUL) 3349 echo_output = TRUE; 3350 if (STRNCMP(s, "silent", 6) == 0) 3351 ++msg_silent; 3352 if (STRCMP(s, "silent!") == 0) 3353 { 3354 emsg_silent = TRUE; 3355 emsg_noredir = TRUE; 3356 } 3357 } 3358 else 3359 ++msg_silent; 3360 3361 if (redir_execute) 3362 save_ga = redir_execute_ga; 3363 ga_init2(&redir_execute_ga, (int)sizeof(char), 500); 3364 redir_execute = TRUE; 3365 redir_off = FALSE; 3366 if (!echo_output) 3367 msg_col = 0; // prevent leading spaces 3368 3369 if (cmd != NULL) 3370 do_cmdline_cmd(cmd); 3371 else 3372 { 3373 listitem_T *item = list->lv_first; 3374 3375 do_cmdline(NULL, get_list_line, (void *)&item, 3376 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED); 3377 --list->lv_refcount; 3378 } 3379 3380 /* Need to append a NUL to the result. */ 3381 if (ga_grow(&redir_execute_ga, 1) == OK) 3382 { 3383 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL; 3384 rettv->vval.v_string = redir_execute_ga.ga_data; 3385 } 3386 else 3387 { 3388 ga_clear(&redir_execute_ga); 3389 rettv->vval.v_string = NULL; 3390 } 3391 msg_silent = save_msg_silent; 3392 emsg_silent = save_emsg_silent; 3393 emsg_noredir = save_emsg_noredir; 3394 3395 redir_execute = save_redir_execute; 3396 if (redir_execute) 3397 redir_execute_ga = save_ga; 3398 redir_off = save_redir_off; 3399 3400 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line. 3401 if (echo_output) 3402 // When not working silently: put it in column zero. A following 3403 // "echon" will overwrite the message, unavoidably. 3404 msg_col = 0; 3405 else 3406 // When working silently: Put it back where it was, since nothing 3407 // should have been written. 3408 msg_col = save_msg_col; 3409 } 3410 3411 /* 3412 * "exepath()" function 3413 */ 3414 static void 3415 f_exepath(typval_T *argvars, typval_T *rettv) 3416 { 3417 char_u *p = NULL; 3418 3419 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE); 3420 rettv->v_type = VAR_STRING; 3421 rettv->vval.v_string = p; 3422 } 3423 3424 /* 3425 * "exists()" function 3426 */ 3427 static void 3428 f_exists(typval_T *argvars, typval_T *rettv) 3429 { 3430 char_u *p; 3431 int n = FALSE; 3432 3433 p = tv_get_string(&argvars[0]); 3434 if (*p == '$') /* environment variable */ 3435 { 3436 /* first try "normal" environment variables (fast) */ 3437 if (mch_getenv(p + 1) != NULL) 3438 n = TRUE; 3439 else 3440 { 3441 /* try expanding things like $VIM and ${HOME} */ 3442 p = expand_env_save(p); 3443 if (p != NULL && *p != '$') 3444 n = TRUE; 3445 vim_free(p); 3446 } 3447 } 3448 else if (*p == '&' || *p == '+') /* option */ 3449 { 3450 n = (get_option_tv(&p, NULL, TRUE) == OK); 3451 if (*skipwhite(p) != NUL) 3452 n = FALSE; /* trailing garbage */ 3453 } 3454 else if (*p == '*') /* internal or user defined function */ 3455 { 3456 n = function_exists(p + 1, FALSE); 3457 } 3458 else if (*p == ':') 3459 { 3460 n = cmd_exists(p + 1); 3461 } 3462 else if (*p == '#') 3463 { 3464 if (p[1] == '#') 3465 n = autocmd_supported(p + 2); 3466 else 3467 n = au_exists(p + 1); 3468 } 3469 else /* internal variable */ 3470 { 3471 n = var_exists(p); 3472 } 3473 3474 rettv->vval.v_number = n; 3475 } 3476 3477 #ifdef FEAT_FLOAT 3478 /* 3479 * "exp()" function 3480 */ 3481 static void 3482 f_exp(typval_T *argvars, typval_T *rettv) 3483 { 3484 float_T f = 0.0; 3485 3486 rettv->v_type = VAR_FLOAT; 3487 if (get_float_arg(argvars, &f) == OK) 3488 rettv->vval.v_float = exp(f); 3489 else 3490 rettv->vval.v_float = 0.0; 3491 } 3492 #endif 3493 3494 /* 3495 * "expand()" function 3496 */ 3497 static void 3498 f_expand(typval_T *argvars, typval_T *rettv) 3499 { 3500 char_u *s; 3501 int len; 3502 char *errormsg; 3503 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND; 3504 expand_T xpc; 3505 int error = FALSE; 3506 char_u *result; 3507 3508 rettv->v_type = VAR_STRING; 3509 if (argvars[1].v_type != VAR_UNKNOWN 3510 && argvars[2].v_type != VAR_UNKNOWN 3511 && tv_get_number_chk(&argvars[2], &error) 3512 && !error) 3513 { 3514 rettv_list_set(rettv, NULL); 3515 } 3516 3517 s = tv_get_string(&argvars[0]); 3518 if (*s == '%' || *s == '#' || *s == '<') 3519 { 3520 ++emsg_off; 3521 result = eval_vars(s, s, &len, NULL, &errormsg, NULL); 3522 --emsg_off; 3523 if (rettv->v_type == VAR_LIST) 3524 { 3525 if (rettv_list_alloc(rettv) != FAIL && result != NULL) 3526 list_append_string(rettv->vval.v_list, result, -1); 3527 else 3528 vim_free(result); 3529 } 3530 else 3531 rettv->vval.v_string = result; 3532 } 3533 else 3534 { 3535 /* When the optional second argument is non-zero, don't remove matches 3536 * for 'wildignore' and don't put matches for 'suffixes' at the end. */ 3537 if (argvars[1].v_type != VAR_UNKNOWN 3538 && tv_get_number_chk(&argvars[1], &error)) 3539 options |= WILD_KEEP_ALL; 3540 if (!error) 3541 { 3542 ExpandInit(&xpc); 3543 xpc.xp_context = EXPAND_FILES; 3544 if (p_wic) 3545 options += WILD_ICASE; 3546 if (rettv->v_type == VAR_STRING) 3547 rettv->vval.v_string = ExpandOne(&xpc, s, NULL, 3548 options, WILD_ALL); 3549 else if (rettv_list_alloc(rettv) != FAIL) 3550 { 3551 int i; 3552 3553 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP); 3554 for (i = 0; i < xpc.xp_numfiles; i++) 3555 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); 3556 ExpandCleanup(&xpc); 3557 } 3558 } 3559 else 3560 rettv->vval.v_string = NULL; 3561 } 3562 } 3563 3564 /* 3565 * "extend(list, list [, idx])" function 3566 * "extend(dict, dict [, action])" function 3567 */ 3568 static void 3569 f_extend(typval_T *argvars, typval_T *rettv) 3570 { 3571 char_u *arg_errmsg = (char_u *)N_("extend() argument"); 3572 3573 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) 3574 { 3575 list_T *l1, *l2; 3576 listitem_T *item; 3577 long before; 3578 int error = FALSE; 3579 3580 l1 = argvars[0].vval.v_list; 3581 l2 = argvars[1].vval.v_list; 3582 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE) 3583 && l2 != NULL) 3584 { 3585 if (argvars[2].v_type != VAR_UNKNOWN) 3586 { 3587 before = (long)tv_get_number_chk(&argvars[2], &error); 3588 if (error) 3589 return; /* type error; errmsg already given */ 3590 3591 if (before == l1->lv_len) 3592 item = NULL; 3593 else 3594 { 3595 item = list_find(l1, before); 3596 if (item == NULL) 3597 { 3598 semsg(_(e_listidx), before); 3599 return; 3600 } 3601 } 3602 } 3603 else 3604 item = NULL; 3605 list_extend(l1, l2, item); 3606 3607 copy_tv(&argvars[0], rettv); 3608 } 3609 } 3610 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) 3611 { 3612 dict_T *d1, *d2; 3613 char_u *action; 3614 int i; 3615 3616 d1 = argvars[0].vval.v_dict; 3617 d2 = argvars[1].vval.v_dict; 3618 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE) 3619 && d2 != NULL) 3620 { 3621 /* Check the third argument. */ 3622 if (argvars[2].v_type != VAR_UNKNOWN) 3623 { 3624 static char *(av[]) = {"keep", "force", "error"}; 3625 3626 action = tv_get_string_chk(&argvars[2]); 3627 if (action == NULL) 3628 return; /* type error; errmsg already given */ 3629 for (i = 0; i < 3; ++i) 3630 if (STRCMP(action, av[i]) == 0) 3631 break; 3632 if (i == 3) 3633 { 3634 semsg(_(e_invarg2), action); 3635 return; 3636 } 3637 } 3638 else 3639 action = (char_u *)"force"; 3640 3641 dict_extend(d1, d2, action); 3642 3643 copy_tv(&argvars[0], rettv); 3644 } 3645 } 3646 else 3647 semsg(_(e_listdictarg), "extend()"); 3648 } 3649 3650 /* 3651 * "feedkeys()" function 3652 */ 3653 static void 3654 f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED) 3655 { 3656 int remap = TRUE; 3657 int insert = FALSE; 3658 char_u *keys, *flags; 3659 char_u nbuf[NUMBUFLEN]; 3660 int typed = FALSE; 3661 int execute = FALSE; 3662 int dangerous = FALSE; 3663 int lowlevel = FALSE; 3664 char_u *keys_esc; 3665 3666 /* This is not allowed in the sandbox. If the commands would still be 3667 * executed in the sandbox it would be OK, but it probably happens later, 3668 * when "sandbox" is no longer set. */ 3669 if (check_secure()) 3670 return; 3671 3672 keys = tv_get_string(&argvars[0]); 3673 3674 if (argvars[1].v_type != VAR_UNKNOWN) 3675 { 3676 flags = tv_get_string_buf(&argvars[1], nbuf); 3677 for ( ; *flags != NUL; ++flags) 3678 { 3679 switch (*flags) 3680 { 3681 case 'n': remap = FALSE; break; 3682 case 'm': remap = TRUE; break; 3683 case 't': typed = TRUE; break; 3684 case 'i': insert = TRUE; break; 3685 case 'x': execute = TRUE; break; 3686 case '!': dangerous = TRUE; break; 3687 case 'L': lowlevel = TRUE; break; 3688 } 3689 } 3690 } 3691 3692 if (*keys != NUL || execute) 3693 { 3694 /* Need to escape K_SPECIAL and CSI before putting the string in the 3695 * typeahead buffer. */ 3696 keys_esc = vim_strsave_escape_csi(keys); 3697 if (keys_esc != NULL) 3698 { 3699 if (lowlevel) 3700 { 3701 #ifdef USE_INPUT_BUF 3702 add_to_input_buf(keys, (int)STRLEN(keys)); 3703 #else 3704 emsg(_("E980: lowlevel input not supported")); 3705 #endif 3706 } 3707 else 3708 { 3709 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), 3710 insert ? 0 : typebuf.tb_len, !typed, FALSE); 3711 if (vgetc_busy 3712 #ifdef FEAT_TIMERS 3713 || timer_busy 3714 #endif 3715 ) 3716 typebuf_was_filled = TRUE; 3717 } 3718 vim_free(keys_esc); 3719 3720 if (execute) 3721 { 3722 int save_msg_scroll = msg_scroll; 3723 3724 /* Avoid a 1 second delay when the keys start Insert mode. */ 3725 msg_scroll = FALSE; 3726 3727 if (!dangerous) 3728 ++ex_normal_busy; 3729 exec_normal(TRUE, FALSE, TRUE); 3730 if (!dangerous) 3731 --ex_normal_busy; 3732 3733 msg_scroll |= save_msg_scroll; 3734 } 3735 } 3736 } 3737 } 3738 3739 /* 3740 * "filereadable()" function 3741 */ 3742 static void 3743 f_filereadable(typval_T *argvars, typval_T *rettv) 3744 { 3745 int fd; 3746 char_u *p; 3747 int n; 3748 3749 #ifndef O_NONBLOCK 3750 # define O_NONBLOCK 0 3751 #endif 3752 p = tv_get_string(&argvars[0]); 3753 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p, 3754 O_RDONLY | O_NONBLOCK, 0)) >= 0) 3755 { 3756 n = TRUE; 3757 close(fd); 3758 } 3759 else 3760 n = FALSE; 3761 3762 rettv->vval.v_number = n; 3763 } 3764 3765 /* 3766 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have 3767 * rights to write into. 3768 */ 3769 static void 3770 f_filewritable(typval_T *argvars, typval_T *rettv) 3771 { 3772 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0])); 3773 } 3774 3775 static void 3776 findfilendir( 3777 typval_T *argvars UNUSED, 3778 typval_T *rettv, 3779 int find_what UNUSED) 3780 { 3781 #ifdef FEAT_SEARCHPATH 3782 char_u *fname; 3783 char_u *fresult = NULL; 3784 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; 3785 char_u *p; 3786 char_u pathbuf[NUMBUFLEN]; 3787 int count = 1; 3788 int first = TRUE; 3789 int error = FALSE; 3790 #endif 3791 3792 rettv->vval.v_string = NULL; 3793 rettv->v_type = VAR_STRING; 3794 3795 #ifdef FEAT_SEARCHPATH 3796 fname = tv_get_string(&argvars[0]); 3797 3798 if (argvars[1].v_type != VAR_UNKNOWN) 3799 { 3800 p = tv_get_string_buf_chk(&argvars[1], pathbuf); 3801 if (p == NULL) 3802 error = TRUE; 3803 else 3804 { 3805 if (*p != NUL) 3806 path = p; 3807 3808 if (argvars[2].v_type != VAR_UNKNOWN) 3809 count = (int)tv_get_number_chk(&argvars[2], &error); 3810 } 3811 } 3812 3813 if (count < 0 && rettv_list_alloc(rettv) == FAIL) 3814 error = TRUE; 3815 3816 if (*fname != NUL && !error) 3817 { 3818 do 3819 { 3820 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) 3821 vim_free(fresult); 3822 fresult = find_file_in_path_option(first ? fname : NULL, 3823 first ? (int)STRLEN(fname) : 0, 3824 0, first, path, 3825 find_what, 3826 curbuf->b_ffname, 3827 find_what == FINDFILE_DIR 3828 ? (char_u *)"" : curbuf->b_p_sua); 3829 first = FALSE; 3830 3831 if (fresult != NULL && rettv->v_type == VAR_LIST) 3832 list_append_string(rettv->vval.v_list, fresult, -1); 3833 3834 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL); 3835 } 3836 3837 if (rettv->v_type == VAR_STRING) 3838 rettv->vval.v_string = fresult; 3839 #endif 3840 } 3841 3842 /* 3843 * "filter()" function 3844 */ 3845 static void 3846 f_filter(typval_T *argvars, typval_T *rettv) 3847 { 3848 filter_map(argvars, rettv, FALSE); 3849 } 3850 3851 /* 3852 * "finddir({fname}[, {path}[, {count}]])" function 3853 */ 3854 static void 3855 f_finddir(typval_T *argvars, typval_T *rettv) 3856 { 3857 findfilendir(argvars, rettv, FINDFILE_DIR); 3858 } 3859 3860 /* 3861 * "findfile({fname}[, {path}[, {count}]])" function 3862 */ 3863 static void 3864 f_findfile(typval_T *argvars, typval_T *rettv) 3865 { 3866 findfilendir(argvars, rettv, FINDFILE_FILE); 3867 } 3868 3869 #ifdef FEAT_FLOAT 3870 /* 3871 * "float2nr({float})" function 3872 */ 3873 static void 3874 f_float2nr(typval_T *argvars, typval_T *rettv) 3875 { 3876 float_T f = 0.0; 3877 3878 if (get_float_arg(argvars, &f) == OK) 3879 { 3880 if (f <= -VARNUM_MAX + DBL_EPSILON) 3881 rettv->vval.v_number = -VARNUM_MAX; 3882 else if (f >= VARNUM_MAX - DBL_EPSILON) 3883 rettv->vval.v_number = VARNUM_MAX; 3884 else 3885 rettv->vval.v_number = (varnumber_T)f; 3886 } 3887 } 3888 3889 /* 3890 * "floor({float})" function 3891 */ 3892 static void 3893 f_floor(typval_T *argvars, typval_T *rettv) 3894 { 3895 float_T f = 0.0; 3896 3897 rettv->v_type = VAR_FLOAT; 3898 if (get_float_arg(argvars, &f) == OK) 3899 rettv->vval.v_float = floor(f); 3900 else 3901 rettv->vval.v_float = 0.0; 3902 } 3903 3904 /* 3905 * "fmod()" function 3906 */ 3907 static void 3908 f_fmod(typval_T *argvars, typval_T *rettv) 3909 { 3910 float_T fx = 0.0, fy = 0.0; 3911 3912 rettv->v_type = VAR_FLOAT; 3913 if (get_float_arg(argvars, &fx) == OK 3914 && get_float_arg(&argvars[1], &fy) == OK) 3915 rettv->vval.v_float = fmod(fx, fy); 3916 else 3917 rettv->vval.v_float = 0.0; 3918 } 3919 #endif 3920 3921 /* 3922 * "fnameescape({string})" function 3923 */ 3924 static void 3925 f_fnameescape(typval_T *argvars, typval_T *rettv) 3926 { 3927 rettv->vval.v_string = vim_strsave_fnameescape( 3928 tv_get_string(&argvars[0]), FALSE); 3929 rettv->v_type = VAR_STRING; 3930 } 3931 3932 /* 3933 * "fnamemodify({fname}, {mods})" function 3934 */ 3935 static void 3936 f_fnamemodify(typval_T *argvars, typval_T *rettv) 3937 { 3938 char_u *fname; 3939 char_u *mods; 3940 int usedlen = 0; 3941 int len; 3942 char_u *fbuf = NULL; 3943 char_u buf[NUMBUFLEN]; 3944 3945 fname = tv_get_string_chk(&argvars[0]); 3946 mods = tv_get_string_buf_chk(&argvars[1], buf); 3947 if (fname == NULL || mods == NULL) 3948 fname = NULL; 3949 else 3950 { 3951 len = (int)STRLEN(fname); 3952 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len); 3953 } 3954 3955 rettv->v_type = VAR_STRING; 3956 if (fname == NULL) 3957 rettv->vval.v_string = NULL; 3958 else 3959 rettv->vval.v_string = vim_strnsave(fname, len); 3960 vim_free(fbuf); 3961 } 3962 3963 /* 3964 * "foldclosed()" function 3965 */ 3966 static void 3967 foldclosed_both( 3968 typval_T *argvars UNUSED, 3969 typval_T *rettv, 3970 int end UNUSED) 3971 { 3972 #ifdef FEAT_FOLDING 3973 linenr_T lnum; 3974 linenr_T first, last; 3975 3976 lnum = tv_get_lnum(argvars); 3977 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) 3978 { 3979 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL)) 3980 { 3981 if (end) 3982 rettv->vval.v_number = (varnumber_T)last; 3983 else 3984 rettv->vval.v_number = (varnumber_T)first; 3985 return; 3986 } 3987 } 3988 #endif 3989 rettv->vval.v_number = -1; 3990 } 3991 3992 /* 3993 * "foldclosed()" function 3994 */ 3995 static void 3996 f_foldclosed(typval_T *argvars, typval_T *rettv) 3997 { 3998 foldclosed_both(argvars, rettv, FALSE); 3999 } 4000 4001 /* 4002 * "foldclosedend()" function 4003 */ 4004 static void 4005 f_foldclosedend(typval_T *argvars, typval_T *rettv) 4006 { 4007 foldclosed_both(argvars, rettv, TRUE); 4008 } 4009 4010 /* 4011 * "foldlevel()" function 4012 */ 4013 static void 4014 f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 4015 { 4016 #ifdef FEAT_FOLDING 4017 linenr_T lnum; 4018 4019 lnum = tv_get_lnum(argvars); 4020 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) 4021 rettv->vval.v_number = foldLevel(lnum); 4022 #endif 4023 } 4024 4025 /* 4026 * "foldtext()" function 4027 */ 4028 static void 4029 f_foldtext(typval_T *argvars UNUSED, typval_T *rettv) 4030 { 4031 #ifdef FEAT_FOLDING 4032 linenr_T foldstart; 4033 linenr_T foldend; 4034 char_u *dashes; 4035 linenr_T lnum; 4036 char_u *s; 4037 char_u *r; 4038 int len; 4039 char *txt; 4040 long count; 4041 #endif 4042 4043 rettv->v_type = VAR_STRING; 4044 rettv->vval.v_string = NULL; 4045 #ifdef FEAT_FOLDING 4046 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART); 4047 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND); 4048 dashes = get_vim_var_str(VV_FOLDDASHES); 4049 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count 4050 && dashes != NULL) 4051 { 4052 /* Find first non-empty line in the fold. */ 4053 for (lnum = foldstart; lnum < foldend; ++lnum) 4054 if (!linewhite(lnum)) 4055 break; 4056 4057 /* Find interesting text in this line. */ 4058 s = skipwhite(ml_get(lnum)); 4059 /* skip C comment-start */ 4060 if (s[0] == '/' && (s[1] == '*' || s[1] == '/')) 4061 { 4062 s = skipwhite(s + 2); 4063 if (*skipwhite(s) == NUL 4064 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND)) 4065 { 4066 s = skipwhite(ml_get(lnum + 1)); 4067 if (*s == '*') 4068 s = skipwhite(s + 1); 4069 } 4070 } 4071 count = (long)(foldend - foldstart + 1); 4072 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count); 4073 r = alloc((unsigned)(STRLEN(txt) 4074 + STRLEN(dashes) /* for %s */ 4075 + 20 /* for %3ld */ 4076 + STRLEN(s))); /* concatenated */ 4077 if (r != NULL) 4078 { 4079 sprintf((char *)r, txt, dashes, count); 4080 len = (int)STRLEN(r); 4081 STRCAT(r, s); 4082 /* remove 'foldmarker' and 'commentstring' */ 4083 foldtext_cleanup(r + len); 4084 rettv->vval.v_string = r; 4085 } 4086 } 4087 #endif 4088 } 4089 4090 /* 4091 * "foldtextresult(lnum)" function 4092 */ 4093 static void 4094 f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv) 4095 { 4096 #ifdef FEAT_FOLDING 4097 linenr_T lnum; 4098 char_u *text; 4099 char_u buf[FOLD_TEXT_LEN]; 4100 foldinfo_T foldinfo; 4101 int fold_count; 4102 static int entered = FALSE; 4103 #endif 4104 4105 rettv->v_type = VAR_STRING; 4106 rettv->vval.v_string = NULL; 4107 #ifdef FEAT_FOLDING 4108 if (entered) 4109 return; /* reject recursive use */ 4110 entered = TRUE; 4111 4112 lnum = tv_get_lnum(argvars); 4113 /* treat illegal types and illegal string values for {lnum} the same */ 4114 if (lnum < 0) 4115 lnum = 0; 4116 fold_count = foldedCount(curwin, lnum, &foldinfo); 4117 if (fold_count > 0) 4118 { 4119 text = get_foldtext(curwin, lnum, lnum + fold_count - 1, 4120 &foldinfo, buf); 4121 if (text == buf) 4122 text = vim_strsave(text); 4123 rettv->vval.v_string = text; 4124 } 4125 4126 entered = FALSE; 4127 #endif 4128 } 4129 4130 /* 4131 * "foreground()" function 4132 */ 4133 static void 4134 f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 4135 { 4136 #ifdef FEAT_GUI 4137 if (gui.in_use) 4138 gui_mch_set_foreground(); 4139 #else 4140 # ifdef WIN32 4141 win32_set_foreground(); 4142 # endif 4143 #endif 4144 } 4145 4146 static void 4147 common_function(typval_T *argvars, typval_T *rettv, int is_funcref) 4148 { 4149 char_u *s; 4150 char_u *name; 4151 int use_string = FALSE; 4152 partial_T *arg_pt = NULL; 4153 char_u *trans_name = NULL; 4154 4155 if (argvars[0].v_type == VAR_FUNC) 4156 { 4157 /* function(MyFunc, [arg], dict) */ 4158 s = argvars[0].vval.v_string; 4159 } 4160 else if (argvars[0].v_type == VAR_PARTIAL 4161 && argvars[0].vval.v_partial != NULL) 4162 { 4163 /* function(dict.MyFunc, [arg]) */ 4164 arg_pt = argvars[0].vval.v_partial; 4165 s = partial_name(arg_pt); 4166 } 4167 else 4168 { 4169 /* function('MyFunc', [arg], dict) */ 4170 s = tv_get_string(&argvars[0]); 4171 use_string = TRUE; 4172 } 4173 4174 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref) 4175 { 4176 name = s; 4177 trans_name = trans_function_name(&name, FALSE, 4178 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL); 4179 if (*name != NUL) 4180 s = NULL; 4181 } 4182 4183 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)) 4184 || (is_funcref && trans_name == NULL)) 4185 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s); 4186 /* Don't check an autoload name for existence here. */ 4187 else if (trans_name != NULL && (is_funcref 4188 ? find_func(trans_name) == NULL 4189 : !translated_function_exists(trans_name))) 4190 semsg(_("E700: Unknown function: %s"), s); 4191 else 4192 { 4193 int dict_idx = 0; 4194 int arg_idx = 0; 4195 list_T *list = NULL; 4196 4197 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0) 4198 { 4199 char sid_buf[25]; 4200 int off = *s == 's' ? 2 : 5; 4201 4202 /* Expand s: and <SID> into <SNR>nr_, so that the function can 4203 * also be called from another script. Using trans_function_name() 4204 * would also work, but some plugins depend on the name being 4205 * printable text. */ 4206 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid); 4207 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1)); 4208 if (name != NULL) 4209 { 4210 STRCPY(name, sid_buf); 4211 STRCAT(name, s + off); 4212 } 4213 } 4214 else 4215 name = vim_strsave(s); 4216 4217 if (argvars[1].v_type != VAR_UNKNOWN) 4218 { 4219 if (argvars[2].v_type != VAR_UNKNOWN) 4220 { 4221 /* function(name, [args], dict) */ 4222 arg_idx = 1; 4223 dict_idx = 2; 4224 } 4225 else if (argvars[1].v_type == VAR_DICT) 4226 /* function(name, dict) */ 4227 dict_idx = 1; 4228 else 4229 /* function(name, [args]) */ 4230 arg_idx = 1; 4231 if (dict_idx > 0) 4232 { 4233 if (argvars[dict_idx].v_type != VAR_DICT) 4234 { 4235 emsg(_("E922: expected a dict")); 4236 vim_free(name); 4237 goto theend; 4238 } 4239 if (argvars[dict_idx].vval.v_dict == NULL) 4240 dict_idx = 0; 4241 } 4242 if (arg_idx > 0) 4243 { 4244 if (argvars[arg_idx].v_type != VAR_LIST) 4245 { 4246 emsg(_("E923: Second argument of function() must be a list or a dict")); 4247 vim_free(name); 4248 goto theend; 4249 } 4250 list = argvars[arg_idx].vval.v_list; 4251 if (list == NULL || list->lv_len == 0) 4252 arg_idx = 0; 4253 } 4254 } 4255 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref) 4256 { 4257 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T)); 4258 4259 /* result is a VAR_PARTIAL */ 4260 if (pt == NULL) 4261 vim_free(name); 4262 else 4263 { 4264 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0)) 4265 { 4266 listitem_T *li; 4267 int i = 0; 4268 int arg_len = 0; 4269 int lv_len = 0; 4270 4271 if (arg_pt != NULL) 4272 arg_len = arg_pt->pt_argc; 4273 if (list != NULL) 4274 lv_len = list->lv_len; 4275 pt->pt_argc = arg_len + lv_len; 4276 pt->pt_argv = (typval_T *)alloc( 4277 sizeof(typval_T) * pt->pt_argc); 4278 if (pt->pt_argv == NULL) 4279 { 4280 vim_free(pt); 4281 vim_free(name); 4282 goto theend; 4283 } 4284 for (i = 0; i < arg_len; i++) 4285 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]); 4286 if (lv_len > 0) 4287 for (li = list->lv_first; li != NULL; 4288 li = li->li_next) 4289 copy_tv(&li->li_tv, &pt->pt_argv[i++]); 4290 } 4291 4292 /* For "function(dict.func, [], dict)" and "func" is a partial 4293 * use "dict". That is backwards compatible. */ 4294 if (dict_idx > 0) 4295 { 4296 /* The dict is bound explicitly, pt_auto is FALSE. */ 4297 pt->pt_dict = argvars[dict_idx].vval.v_dict; 4298 ++pt->pt_dict->dv_refcount; 4299 } 4300 else if (arg_pt != NULL) 4301 { 4302 /* If the dict was bound automatically the result is also 4303 * bound automatically. */ 4304 pt->pt_dict = arg_pt->pt_dict; 4305 pt->pt_auto = arg_pt->pt_auto; 4306 if (pt->pt_dict != NULL) 4307 ++pt->pt_dict->dv_refcount; 4308 } 4309 4310 pt->pt_refcount = 1; 4311 if (arg_pt != NULL && arg_pt->pt_func != NULL) 4312 { 4313 pt->pt_func = arg_pt->pt_func; 4314 func_ptr_ref(pt->pt_func); 4315 vim_free(name); 4316 } 4317 else if (is_funcref) 4318 { 4319 pt->pt_func = find_func(trans_name); 4320 func_ptr_ref(pt->pt_func); 4321 vim_free(name); 4322 } 4323 else 4324 { 4325 pt->pt_name = name; 4326 func_ref(name); 4327 } 4328 } 4329 rettv->v_type = VAR_PARTIAL; 4330 rettv->vval.v_partial = pt; 4331 } 4332 else 4333 { 4334 /* result is a VAR_FUNC */ 4335 rettv->v_type = VAR_FUNC; 4336 rettv->vval.v_string = name; 4337 func_ref(name); 4338 } 4339 } 4340 theend: 4341 vim_free(trans_name); 4342 } 4343 4344 /* 4345 * "funcref()" function 4346 */ 4347 static void 4348 f_funcref(typval_T *argvars, typval_T *rettv) 4349 { 4350 common_function(argvars, rettv, TRUE); 4351 } 4352 4353 /* 4354 * "function()" function 4355 */ 4356 static void 4357 f_function(typval_T *argvars, typval_T *rettv) 4358 { 4359 common_function(argvars, rettv, FALSE); 4360 } 4361 4362 /* 4363 * "garbagecollect()" function 4364 */ 4365 static void 4366 f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED) 4367 { 4368 /* This is postponed until we are back at the toplevel, because we may be 4369 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */ 4370 want_garbage_collect = TRUE; 4371 4372 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1) 4373 garbage_collect_at_exit = TRUE; 4374 } 4375 4376 /* 4377 * "get()" function 4378 */ 4379 static void 4380 f_get(typval_T *argvars, typval_T *rettv) 4381 { 4382 listitem_T *li; 4383 list_T *l; 4384 dictitem_T *di; 4385 dict_T *d; 4386 typval_T *tv = NULL; 4387 4388 if (argvars[0].v_type == VAR_BLOB) 4389 { 4390 int error = FALSE; 4391 int idx = tv_get_number_chk(&argvars[1], &error); 4392 4393 if (!error) 4394 { 4395 rettv->v_type = VAR_NUMBER; 4396 if (idx < 0) 4397 idx = blob_len(argvars[0].vval.v_blob) + idx; 4398 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob)) 4399 rettv->vval.v_number = -1; 4400 else 4401 { 4402 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx); 4403 tv = rettv; 4404 } 4405 } 4406 } 4407 else if (argvars[0].v_type == VAR_LIST) 4408 { 4409 if ((l = argvars[0].vval.v_list) != NULL) 4410 { 4411 int error = FALSE; 4412 4413 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error)); 4414 if (!error && li != NULL) 4415 tv = &li->li_tv; 4416 } 4417 } 4418 else if (argvars[0].v_type == VAR_DICT) 4419 { 4420 if ((d = argvars[0].vval.v_dict) != NULL) 4421 { 4422 di = dict_find(d, tv_get_string(&argvars[1]), -1); 4423 if (di != NULL) 4424 tv = &di->di_tv; 4425 } 4426 } 4427 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC) 4428 { 4429 partial_T *pt; 4430 partial_T fref_pt; 4431 4432 if (argvars[0].v_type == VAR_PARTIAL) 4433 pt = argvars[0].vval.v_partial; 4434 else 4435 { 4436 vim_memset(&fref_pt, 0, sizeof(fref_pt)); 4437 fref_pt.pt_name = argvars[0].vval.v_string; 4438 pt = &fref_pt; 4439 } 4440 4441 if (pt != NULL) 4442 { 4443 char_u *what = tv_get_string(&argvars[1]); 4444 char_u *n; 4445 4446 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0) 4447 { 4448 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING); 4449 n = partial_name(pt); 4450 if (n == NULL) 4451 rettv->vval.v_string = NULL; 4452 else 4453 { 4454 rettv->vval.v_string = vim_strsave(n); 4455 if (rettv->v_type == VAR_FUNC) 4456 func_ref(rettv->vval.v_string); 4457 } 4458 } 4459 else if (STRCMP(what, "dict") == 0) 4460 rettv_dict_set(rettv, pt->pt_dict); 4461 else if (STRCMP(what, "args") == 0) 4462 { 4463 rettv->v_type = VAR_LIST; 4464 if (rettv_list_alloc(rettv) == OK) 4465 { 4466 int i; 4467 4468 for (i = 0; i < pt->pt_argc; ++i) 4469 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]); 4470 } 4471 } 4472 else 4473 semsg(_(e_invarg2), what); 4474 return; 4475 } 4476 } 4477 else 4478 semsg(_(e_listdictblobarg), "get()"); 4479 4480 if (tv == NULL) 4481 { 4482 if (argvars[2].v_type != VAR_UNKNOWN) 4483 copy_tv(&argvars[2], rettv); 4484 } 4485 else 4486 copy_tv(tv, rettv); 4487 } 4488 4489 /* 4490 * Returns buffer options, variables and other attributes in a dictionary. 4491 */ 4492 static dict_T * 4493 get_buffer_info(buf_T *buf) 4494 { 4495 dict_T *dict; 4496 tabpage_T *tp; 4497 win_T *wp; 4498 list_T *windows; 4499 4500 dict = dict_alloc(); 4501 if (dict == NULL) 4502 return NULL; 4503 4504 dict_add_number(dict, "bufnr", buf->b_fnum); 4505 dict_add_string(dict, "name", buf->b_ffname); 4506 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum 4507 : buflist_findlnum(buf)); 4508 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL); 4509 dict_add_number(dict, "listed", buf->b_p_bl); 4510 dict_add_number(dict, "changed", bufIsChanged(buf)); 4511 dict_add_number(dict, "changedtick", CHANGEDTICK(buf)); 4512 dict_add_number(dict, "hidden", 4513 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0); 4514 4515 /* Get a reference to buffer variables */ 4516 dict_add_dict(dict, "variables", buf->b_vars); 4517 4518 /* List of windows displaying this buffer */ 4519 windows = list_alloc(); 4520 if (windows != NULL) 4521 { 4522 FOR_ALL_TAB_WINDOWS(tp, wp) 4523 if (wp->w_buffer == buf) 4524 list_append_number(windows, (varnumber_T)wp->w_id); 4525 dict_add_list(dict, "windows", windows); 4526 } 4527 4528 #ifdef FEAT_SIGNS 4529 if (buf->b_signlist != NULL) 4530 { 4531 /* List of signs placed in this buffer */ 4532 list_T *signs = list_alloc(); 4533 if (signs != NULL) 4534 { 4535 get_buffer_signs(buf, signs); 4536 dict_add_list(dict, "signs", signs); 4537 } 4538 } 4539 #endif 4540 4541 return dict; 4542 } 4543 4544 /* 4545 * "getbufinfo()" function 4546 */ 4547 static void 4548 f_getbufinfo(typval_T *argvars, typval_T *rettv) 4549 { 4550 buf_T *buf = NULL; 4551 buf_T *argbuf = NULL; 4552 dict_T *d; 4553 int filtered = FALSE; 4554 int sel_buflisted = FALSE; 4555 int sel_bufloaded = FALSE; 4556 int sel_bufmodified = FALSE; 4557 4558 if (rettv_list_alloc(rettv) != OK) 4559 return; 4560 4561 /* List of all the buffers or selected buffers */ 4562 if (argvars[0].v_type == VAR_DICT) 4563 { 4564 dict_T *sel_d = argvars[0].vval.v_dict; 4565 4566 if (sel_d != NULL) 4567 { 4568 dictitem_T *di; 4569 4570 filtered = TRUE; 4571 4572 di = dict_find(sel_d, (char_u *)"buflisted", -1); 4573 if (di != NULL && tv_get_number(&di->di_tv)) 4574 sel_buflisted = TRUE; 4575 4576 di = dict_find(sel_d, (char_u *)"bufloaded", -1); 4577 if (di != NULL && tv_get_number(&di->di_tv)) 4578 sel_bufloaded = TRUE; 4579 4580 di = dict_find(sel_d, (char_u *)"bufmodified", -1); 4581 if (di != NULL && tv_get_number(&di->di_tv)) 4582 sel_bufmodified = TRUE; 4583 } 4584 } 4585 else if (argvars[0].v_type != VAR_UNKNOWN) 4586 { 4587 /* Information about one buffer. Argument specifies the buffer */ 4588 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */ 4589 ++emsg_off; 4590 argbuf = tv_get_buf(&argvars[0], FALSE); 4591 --emsg_off; 4592 if (argbuf == NULL) 4593 return; 4594 } 4595 4596 /* Return information about all the buffers or a specified buffer */ 4597 FOR_ALL_BUFFERS(buf) 4598 { 4599 if (argbuf != NULL && argbuf != buf) 4600 continue; 4601 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL) 4602 || (sel_buflisted && !buf->b_p_bl) 4603 || (sel_bufmodified && !buf->b_changed))) 4604 continue; 4605 4606 d = get_buffer_info(buf); 4607 if (d != NULL) 4608 list_append_dict(rettv->vval.v_list, d); 4609 if (argbuf != NULL) 4610 return; 4611 } 4612 } 4613 4614 /* 4615 * Get line or list of lines from buffer "buf" into "rettv". 4616 * Return a range (from start to end) of lines in rettv from the specified 4617 * buffer. 4618 * If 'retlist' is TRUE, then the lines are returned as a Vim List. 4619 */ 4620 static void 4621 get_buffer_lines( 4622 buf_T *buf, 4623 linenr_T start, 4624 linenr_T end, 4625 int retlist, 4626 typval_T *rettv) 4627 { 4628 char_u *p; 4629 4630 rettv->v_type = VAR_STRING; 4631 rettv->vval.v_string = NULL; 4632 if (retlist && rettv_list_alloc(rettv) == FAIL) 4633 return; 4634 4635 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0) 4636 return; 4637 4638 if (!retlist) 4639 { 4640 if (start >= 1 && start <= buf->b_ml.ml_line_count) 4641 p = ml_get_buf(buf, start, FALSE); 4642 else 4643 p = (char_u *)""; 4644 rettv->vval.v_string = vim_strsave(p); 4645 } 4646 else 4647 { 4648 if (end < start) 4649 return; 4650 4651 if (start < 1) 4652 start = 1; 4653 if (end > buf->b_ml.ml_line_count) 4654 end = buf->b_ml.ml_line_count; 4655 while (start <= end) 4656 if (list_append_string(rettv->vval.v_list, 4657 ml_get_buf(buf, start++, FALSE), -1) == FAIL) 4658 break; 4659 } 4660 } 4661 4662 /* 4663 * "getbufline()" function 4664 */ 4665 static void 4666 f_getbufline(typval_T *argvars, typval_T *rettv) 4667 { 4668 linenr_T lnum; 4669 linenr_T end; 4670 buf_T *buf; 4671 4672 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */ 4673 ++emsg_off; 4674 buf = tv_get_buf(&argvars[0], FALSE); 4675 --emsg_off; 4676 4677 lnum = tv_get_lnum_buf(&argvars[1], buf); 4678 if (argvars[2].v_type == VAR_UNKNOWN) 4679 end = lnum; 4680 else 4681 end = tv_get_lnum_buf(&argvars[2], buf); 4682 4683 get_buffer_lines(buf, lnum, end, TRUE, rettv); 4684 } 4685 4686 /* 4687 * "getbufvar()" function 4688 */ 4689 static void 4690 f_getbufvar(typval_T *argvars, typval_T *rettv) 4691 { 4692 buf_T *buf; 4693 buf_T *save_curbuf; 4694 char_u *varname; 4695 dictitem_T *v; 4696 int done = FALSE; 4697 4698 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */ 4699 varname = tv_get_string_chk(&argvars[1]); 4700 ++emsg_off; 4701 buf = tv_get_buf(&argvars[0], FALSE); 4702 4703 rettv->v_type = VAR_STRING; 4704 rettv->vval.v_string = NULL; 4705 4706 if (buf != NULL && varname != NULL) 4707 { 4708 /* set curbuf to be our buf, temporarily */ 4709 save_curbuf = curbuf; 4710 curbuf = buf; 4711 4712 if (*varname == '&') 4713 { 4714 if (varname[1] == NUL) 4715 { 4716 /* get all buffer-local options in a dict */ 4717 dict_T *opts = get_winbuf_options(TRUE); 4718 4719 if (opts != NULL) 4720 { 4721 rettv_dict_set(rettv, opts); 4722 done = TRUE; 4723 } 4724 } 4725 else if (get_option_tv(&varname, rettv, TRUE) == OK) 4726 /* buffer-local-option */ 4727 done = TRUE; 4728 } 4729 else 4730 { 4731 /* Look up the variable. */ 4732 /* Let getbufvar({nr}, "") return the "b:" dictionary. */ 4733 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab, 4734 'b', varname, FALSE); 4735 if (v != NULL) 4736 { 4737 copy_tv(&v->di_tv, rettv); 4738 done = TRUE; 4739 } 4740 } 4741 4742 /* restore previous notion of curbuf */ 4743 curbuf = save_curbuf; 4744 } 4745 4746 if (!done && argvars[2].v_type != VAR_UNKNOWN) 4747 /* use the default value */ 4748 copy_tv(&argvars[2], rettv); 4749 4750 --emsg_off; 4751 } 4752 4753 /* 4754 * "getchangelist()" function 4755 */ 4756 static void 4757 f_getchangelist(typval_T *argvars, typval_T *rettv) 4758 { 4759 #ifdef FEAT_JUMPLIST 4760 buf_T *buf; 4761 int i; 4762 list_T *l; 4763 dict_T *d; 4764 #endif 4765 4766 if (rettv_list_alloc(rettv) != OK) 4767 return; 4768 4769 #ifdef FEAT_JUMPLIST 4770 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */ 4771 ++emsg_off; 4772 buf = tv_get_buf(&argvars[0], FALSE); 4773 --emsg_off; 4774 if (buf == NULL) 4775 return; 4776 4777 l = list_alloc(); 4778 if (l == NULL) 4779 return; 4780 4781 if (list_append_list(rettv->vval.v_list, l) == FAIL) 4782 return; 4783 /* 4784 * The current window change list index tracks only the position in the 4785 * current buffer change list. For other buffers, use the change list 4786 * length as the current index. 4787 */ 4788 list_append_number(rettv->vval.v_list, 4789 (varnumber_T)((buf == curwin->w_buffer) 4790 ? curwin->w_changelistidx : buf->b_changelistlen)); 4791 4792 for (i = 0; i < buf->b_changelistlen; ++i) 4793 { 4794 if (buf->b_changelist[i].lnum == 0) 4795 continue; 4796 if ((d = dict_alloc()) == NULL) 4797 return; 4798 if (list_append_dict(l, d) == FAIL) 4799 return; 4800 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum); 4801 dict_add_number(d, "col", (long)buf->b_changelist[i].col); 4802 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd); 4803 } 4804 #endif 4805 } 4806 /* 4807 * "getchar()" function 4808 */ 4809 static void 4810 f_getchar(typval_T *argvars, typval_T *rettv) 4811 { 4812 varnumber_T n; 4813 int error = FALSE; 4814 4815 #ifdef MESSAGE_QUEUE 4816 // vpeekc() used to check for messages, but that caused problems, invoking 4817 // a callback where it was not expected. Some plugins use getchar(1) in a 4818 // loop to await a message, therefore make sure we check for messages here. 4819 parse_queued_messages(); 4820 #endif 4821 4822 /* Position the cursor. Needed after a message that ends in a space. */ 4823 windgoto(msg_row, msg_col); 4824 4825 ++no_mapping; 4826 ++allow_keys; 4827 for (;;) 4828 { 4829 if (argvars[0].v_type == VAR_UNKNOWN) 4830 /* getchar(): blocking wait. */ 4831 n = plain_vgetc(); 4832 else if (tv_get_number_chk(&argvars[0], &error) == 1) 4833 /* getchar(1): only check if char avail */ 4834 n = vpeekc_any(); 4835 else if (error || vpeekc_any() == NUL) 4836 /* illegal argument or getchar(0) and no char avail: return zero */ 4837 n = 0; 4838 else 4839 /* getchar(0) and char avail: return char */ 4840 n = plain_vgetc(); 4841 4842 if (n == K_IGNORE) 4843 continue; 4844 break; 4845 } 4846 --no_mapping; 4847 --allow_keys; 4848 4849 set_vim_var_nr(VV_MOUSE_WIN, 0); 4850 set_vim_var_nr(VV_MOUSE_WINID, 0); 4851 set_vim_var_nr(VV_MOUSE_LNUM, 0); 4852 set_vim_var_nr(VV_MOUSE_COL, 0); 4853 4854 rettv->vval.v_number = n; 4855 if (IS_SPECIAL(n) || mod_mask != 0) 4856 { 4857 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */ 4858 int i = 0; 4859 4860 /* Turn a special key into three bytes, plus modifier. */ 4861 if (mod_mask != 0) 4862 { 4863 temp[i++] = K_SPECIAL; 4864 temp[i++] = KS_MODIFIER; 4865 temp[i++] = mod_mask; 4866 } 4867 if (IS_SPECIAL(n)) 4868 { 4869 temp[i++] = K_SPECIAL; 4870 temp[i++] = K_SECOND(n); 4871 temp[i++] = K_THIRD(n); 4872 } 4873 else if (has_mbyte) 4874 i += (*mb_char2bytes)(n, temp + i); 4875 else 4876 temp[i++] = n; 4877 temp[i++] = NUL; 4878 rettv->v_type = VAR_STRING; 4879 rettv->vval.v_string = vim_strsave(temp); 4880 4881 #ifdef FEAT_MOUSE 4882 if (is_mouse_key(n)) 4883 { 4884 int row = mouse_row; 4885 int col = mouse_col; 4886 win_T *win; 4887 linenr_T lnum; 4888 win_T *wp; 4889 int winnr = 1; 4890 4891 if (row >= 0 && col >= 0) 4892 { 4893 /* Find the window at the mouse coordinates and compute the 4894 * text position. */ 4895 win = mouse_find_win(&row, &col); 4896 if (win == NULL) 4897 return; 4898 (void)mouse_comp_pos(win, &row, &col, &lnum); 4899 for (wp = firstwin; wp != win; wp = wp->w_next) 4900 ++winnr; 4901 set_vim_var_nr(VV_MOUSE_WIN, winnr); 4902 set_vim_var_nr(VV_MOUSE_WINID, win->w_id); 4903 set_vim_var_nr(VV_MOUSE_LNUM, lnum); 4904 set_vim_var_nr(VV_MOUSE_COL, col + 1); 4905 } 4906 } 4907 #endif 4908 } 4909 } 4910 4911 /* 4912 * "getcharmod()" function 4913 */ 4914 static void 4915 f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv) 4916 { 4917 rettv->vval.v_number = mod_mask; 4918 } 4919 4920 /* 4921 * "getcharsearch()" function 4922 */ 4923 static void 4924 f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv) 4925 { 4926 if (rettv_dict_alloc(rettv) != FAIL) 4927 { 4928 dict_T *dict = rettv->vval.v_dict; 4929 4930 dict_add_string(dict, "char", last_csearch()); 4931 dict_add_number(dict, "forward", last_csearch_forward()); 4932 dict_add_number(dict, "until", last_csearch_until()); 4933 } 4934 } 4935 4936 /* 4937 * "getcmdline()" function 4938 */ 4939 static void 4940 f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv) 4941 { 4942 rettv->v_type = VAR_STRING; 4943 rettv->vval.v_string = get_cmdline_str(); 4944 } 4945 4946 /* 4947 * "getcmdpos()" function 4948 */ 4949 static void 4950 f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv) 4951 { 4952 rettv->vval.v_number = get_cmdline_pos() + 1; 4953 } 4954 4955 /* 4956 * "getcmdtype()" function 4957 */ 4958 static void 4959 f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv) 4960 { 4961 rettv->v_type = VAR_STRING; 4962 rettv->vval.v_string = alloc(2); 4963 if (rettv->vval.v_string != NULL) 4964 { 4965 rettv->vval.v_string[0] = get_cmdline_type(); 4966 rettv->vval.v_string[1] = NUL; 4967 } 4968 } 4969 4970 /* 4971 * "getcmdwintype()" function 4972 */ 4973 static void 4974 f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv) 4975 { 4976 rettv->v_type = VAR_STRING; 4977 rettv->vval.v_string = NULL; 4978 #ifdef FEAT_CMDWIN 4979 rettv->vval.v_string = alloc(2); 4980 if (rettv->vval.v_string != NULL) 4981 { 4982 rettv->vval.v_string[0] = cmdwin_type; 4983 rettv->vval.v_string[1] = NUL; 4984 } 4985 #endif 4986 } 4987 4988 #if defined(FEAT_CMDL_COMPL) 4989 /* 4990 * "getcompletion()" function 4991 */ 4992 static void 4993 f_getcompletion(typval_T *argvars, typval_T *rettv) 4994 { 4995 char_u *pat; 4996 expand_T xpc; 4997 int filtered = FALSE; 4998 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH 4999 | WILD_NO_BEEP; 5000 5001 if (argvars[2].v_type != VAR_UNKNOWN) 5002 filtered = tv_get_number_chk(&argvars[2], NULL); 5003 5004 if (p_wic) 5005 options |= WILD_ICASE; 5006 5007 /* For filtered results, 'wildignore' is used */ 5008 if (!filtered) 5009 options |= WILD_KEEP_ALL; 5010 5011 ExpandInit(&xpc); 5012 xpc.xp_pattern = tv_get_string(&argvars[0]); 5013 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); 5014 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1])); 5015 if (xpc.xp_context == EXPAND_NOTHING) 5016 { 5017 if (argvars[1].v_type == VAR_STRING) 5018 semsg(_(e_invarg2), argvars[1].vval.v_string); 5019 else 5020 emsg(_(e_invarg)); 5021 return; 5022 } 5023 5024 # if defined(FEAT_MENU) 5025 if (xpc.xp_context == EXPAND_MENUS) 5026 { 5027 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE); 5028 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); 5029 } 5030 # endif 5031 #ifdef FEAT_CSCOPE 5032 if (xpc.xp_context == EXPAND_CSCOPE) 5033 { 5034 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope); 5035 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); 5036 } 5037 #endif 5038 #ifdef FEAT_SIGNS 5039 if (xpc.xp_context == EXPAND_SIGN) 5040 { 5041 set_context_in_sign_cmd(&xpc, xpc.xp_pattern); 5042 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); 5043 } 5044 #endif 5045 5046 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context); 5047 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL)) 5048 { 5049 int i; 5050 5051 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP); 5052 5053 for (i = 0; i < xpc.xp_numfiles; i++) 5054 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); 5055 } 5056 vim_free(pat); 5057 ExpandCleanup(&xpc); 5058 } 5059 #endif 5060 5061 /* 5062 * "getcwd()" function 5063 */ 5064 static void 5065 f_getcwd(typval_T *argvars, typval_T *rettv) 5066 { 5067 win_T *wp = NULL; 5068 char_u *cwd; 5069 int global = FALSE; 5070 5071 rettv->v_type = VAR_STRING; 5072 rettv->vval.v_string = NULL; 5073 5074 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1) 5075 global = TRUE; 5076 else 5077 wp = find_tabwin(&argvars[0], &argvars[1]); 5078 5079 if (wp != NULL && wp->w_localdir != NULL) 5080 rettv->vval.v_string = vim_strsave(wp->w_localdir); 5081 else if (wp != NULL || global) 5082 { 5083 if (globaldir != NULL) 5084 rettv->vval.v_string = vim_strsave(globaldir); 5085 else 5086 { 5087 cwd = alloc(MAXPATHL); 5088 if (cwd != NULL) 5089 { 5090 if (mch_dirname(cwd, MAXPATHL) != FAIL) 5091 rettv->vval.v_string = vim_strsave(cwd); 5092 vim_free(cwd); 5093 } 5094 } 5095 } 5096 #ifdef BACKSLASH_IN_FILENAME 5097 if (rettv->vval.v_string != NULL) 5098 slash_adjust(rettv->vval.v_string); 5099 #endif 5100 } 5101 5102 /* 5103 * "getfontname()" function 5104 */ 5105 static void 5106 f_getfontname(typval_T *argvars UNUSED, typval_T *rettv) 5107 { 5108 rettv->v_type = VAR_STRING; 5109 rettv->vval.v_string = NULL; 5110 #ifdef FEAT_GUI 5111 if (gui.in_use) 5112 { 5113 GuiFont font; 5114 char_u *name = NULL; 5115 5116 if (argvars[0].v_type == VAR_UNKNOWN) 5117 { 5118 /* Get the "Normal" font. Either the name saved by 5119 * hl_set_font_name() or from the font ID. */ 5120 font = gui.norm_font; 5121 name = hl_get_font_name(); 5122 } 5123 else 5124 { 5125 name = tv_get_string(&argvars[0]); 5126 if (STRCMP(name, "*") == 0) /* don't use font dialog */ 5127 return; 5128 font = gui_mch_get_font(name, FALSE); 5129 if (font == NOFONT) 5130 return; /* Invalid font name, return empty string. */ 5131 } 5132 rettv->vval.v_string = gui_mch_get_fontname(font, name); 5133 if (argvars[0].v_type != VAR_UNKNOWN) 5134 gui_mch_free_font(font); 5135 } 5136 #endif 5137 } 5138 5139 /* 5140 * "getfperm({fname})" function 5141 */ 5142 static void 5143 f_getfperm(typval_T *argvars, typval_T *rettv) 5144 { 5145 char_u *fname; 5146 stat_T st; 5147 char_u *perm = NULL; 5148 char_u flags[] = "rwx"; 5149 int i; 5150 5151 fname = tv_get_string(&argvars[0]); 5152 5153 rettv->v_type = VAR_STRING; 5154 if (mch_stat((char *)fname, &st) >= 0) 5155 { 5156 perm = vim_strsave((char_u *)"---------"); 5157 if (perm != NULL) 5158 { 5159 for (i = 0; i < 9; i++) 5160 { 5161 if (st.st_mode & (1 << (8 - i))) 5162 perm[i] = flags[i % 3]; 5163 } 5164 } 5165 } 5166 rettv->vval.v_string = perm; 5167 } 5168 5169 /* 5170 * "getfsize({fname})" function 5171 */ 5172 static void 5173 f_getfsize(typval_T *argvars, typval_T *rettv) 5174 { 5175 char_u *fname; 5176 stat_T st; 5177 5178 fname = tv_get_string(&argvars[0]); 5179 5180 rettv->v_type = VAR_NUMBER; 5181 5182 if (mch_stat((char *)fname, &st) >= 0) 5183 { 5184 if (mch_isdir(fname)) 5185 rettv->vval.v_number = 0; 5186 else 5187 { 5188 rettv->vval.v_number = (varnumber_T)st.st_size; 5189 5190 /* non-perfect check for overflow */ 5191 if ((off_T)rettv->vval.v_number != (off_T)st.st_size) 5192 rettv->vval.v_number = -2; 5193 } 5194 } 5195 else 5196 rettv->vval.v_number = -1; 5197 } 5198 5199 /* 5200 * "getftime({fname})" function 5201 */ 5202 static void 5203 f_getftime(typval_T *argvars, typval_T *rettv) 5204 { 5205 char_u *fname; 5206 stat_T st; 5207 5208 fname = tv_get_string(&argvars[0]); 5209 5210 if (mch_stat((char *)fname, &st) >= 0) 5211 rettv->vval.v_number = (varnumber_T)st.st_mtime; 5212 else 5213 rettv->vval.v_number = -1; 5214 } 5215 5216 /* 5217 * "getftype({fname})" function 5218 */ 5219 static void 5220 f_getftype(typval_T *argvars, typval_T *rettv) 5221 { 5222 char_u *fname; 5223 stat_T st; 5224 char_u *type = NULL; 5225 char *t; 5226 5227 fname = tv_get_string(&argvars[0]); 5228 5229 rettv->v_type = VAR_STRING; 5230 if (mch_lstat((char *)fname, &st) >= 0) 5231 { 5232 if (S_ISREG(st.st_mode)) 5233 t = "file"; 5234 else if (S_ISDIR(st.st_mode)) 5235 t = "dir"; 5236 else if (S_ISLNK(st.st_mode)) 5237 t = "link"; 5238 else if (S_ISBLK(st.st_mode)) 5239 t = "bdev"; 5240 else if (S_ISCHR(st.st_mode)) 5241 t = "cdev"; 5242 else if (S_ISFIFO(st.st_mode)) 5243 t = "fifo"; 5244 else if (S_ISSOCK(st.st_mode)) 5245 t = "socket"; 5246 else 5247 t = "other"; 5248 type = vim_strsave((char_u *)t); 5249 } 5250 rettv->vval.v_string = type; 5251 } 5252 5253 /* 5254 * "getjumplist()" function 5255 */ 5256 static void 5257 f_getjumplist(typval_T *argvars, typval_T *rettv) 5258 { 5259 #ifdef FEAT_JUMPLIST 5260 win_T *wp; 5261 int i; 5262 list_T *l; 5263 dict_T *d; 5264 #endif 5265 5266 if (rettv_list_alloc(rettv) != OK) 5267 return; 5268 5269 #ifdef FEAT_JUMPLIST 5270 wp = find_tabwin(&argvars[0], &argvars[1]); 5271 if (wp == NULL) 5272 return; 5273 5274 l = list_alloc(); 5275 if (l == NULL) 5276 return; 5277 5278 if (list_append_list(rettv->vval.v_list, l) == FAIL) 5279 return; 5280 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx); 5281 5282 cleanup_jumplist(wp, TRUE); 5283 5284 for (i = 0; i < wp->w_jumplistlen; ++i) 5285 { 5286 if (wp->w_jumplist[i].fmark.mark.lnum == 0) 5287 continue; 5288 if ((d = dict_alloc()) == NULL) 5289 return; 5290 if (list_append_dict(l, d) == FAIL) 5291 return; 5292 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum); 5293 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col); 5294 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd); 5295 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum); 5296 if (wp->w_jumplist[i].fname != NULL) 5297 dict_add_string(d, "filename", wp->w_jumplist[i].fname); 5298 } 5299 #endif 5300 } 5301 5302 /* 5303 * "getline(lnum, [end])" function 5304 */ 5305 static void 5306 f_getline(typval_T *argvars, typval_T *rettv) 5307 { 5308 linenr_T lnum; 5309 linenr_T end; 5310 int retlist; 5311 5312 lnum = tv_get_lnum(argvars); 5313 if (argvars[1].v_type == VAR_UNKNOWN) 5314 { 5315 end = 0; 5316 retlist = FALSE; 5317 } 5318 else 5319 { 5320 end = tv_get_lnum(&argvars[1]); 5321 retlist = TRUE; 5322 } 5323 5324 get_buffer_lines(curbuf, lnum, end, retlist, rettv); 5325 } 5326 5327 #ifdef FEAT_QUICKFIX 5328 static void 5329 get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv) 5330 { 5331 if (what_arg->v_type == VAR_UNKNOWN) 5332 { 5333 if (rettv_list_alloc(rettv) == OK) 5334 if (is_qf || wp != NULL) 5335 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list); 5336 } 5337 else 5338 { 5339 if (rettv_dict_alloc(rettv) == OK) 5340 if (is_qf || (wp != NULL)) 5341 { 5342 if (what_arg->v_type == VAR_DICT) 5343 { 5344 dict_T *d = what_arg->vval.v_dict; 5345 5346 if (d != NULL) 5347 qf_get_properties(wp, d, rettv->vval.v_dict); 5348 } 5349 else 5350 emsg(_(e_dictreq)); 5351 } 5352 } 5353 } 5354 #endif 5355 5356 /* 5357 * "getloclist()" function 5358 */ 5359 static void 5360 f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 5361 { 5362 #ifdef FEAT_QUICKFIX 5363 win_T *wp; 5364 5365 wp = find_win_by_nr_or_id(&argvars[0]); 5366 get_qf_loc_list(FALSE, wp, &argvars[1], rettv); 5367 #endif 5368 } 5369 5370 /* 5371 * "getmatches()" function 5372 */ 5373 static void 5374 f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 5375 { 5376 #ifdef FEAT_SEARCH_EXTRA 5377 dict_T *dict; 5378 matchitem_T *cur = curwin->w_match_head; 5379 int i; 5380 5381 if (rettv_list_alloc(rettv) == OK) 5382 { 5383 while (cur != NULL) 5384 { 5385 dict = dict_alloc(); 5386 if (dict == NULL) 5387 return; 5388 if (cur->match.regprog == NULL) 5389 { 5390 /* match added with matchaddpos() */ 5391 for (i = 0; i < MAXPOSMATCH; ++i) 5392 { 5393 llpos_T *llpos; 5394 char buf[6]; 5395 list_T *l; 5396 5397 llpos = &cur->pos.pos[i]; 5398 if (llpos->lnum == 0) 5399 break; 5400 l = list_alloc(); 5401 if (l == NULL) 5402 break; 5403 list_append_number(l, (varnumber_T)llpos->lnum); 5404 if (llpos->col > 0) 5405 { 5406 list_append_number(l, (varnumber_T)llpos->col); 5407 list_append_number(l, (varnumber_T)llpos->len); 5408 } 5409 sprintf(buf, "pos%d", i + 1); 5410 dict_add_list(dict, buf, l); 5411 } 5412 } 5413 else 5414 { 5415 dict_add_string(dict, "pattern", cur->pattern); 5416 } 5417 dict_add_string(dict, "group", syn_id2name(cur->hlg_id)); 5418 dict_add_number(dict, "priority", (long)cur->priority); 5419 dict_add_number(dict, "id", (long)cur->id); 5420 # if defined(FEAT_CONCEAL) 5421 if (cur->conceal_char) 5422 { 5423 char_u buf[MB_MAXBYTES + 1]; 5424 5425 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL; 5426 dict_add_string(dict, "conceal", (char_u *)&buf); 5427 } 5428 # endif 5429 list_append_dict(rettv->vval.v_list, dict); 5430 cur = cur->next; 5431 } 5432 } 5433 #endif 5434 } 5435 5436 /* 5437 * "getpid()" function 5438 */ 5439 static void 5440 f_getpid(typval_T *argvars UNUSED, typval_T *rettv) 5441 { 5442 rettv->vval.v_number = mch_get_pid(); 5443 } 5444 5445 static void 5446 getpos_both( 5447 typval_T *argvars, 5448 typval_T *rettv, 5449 int getcurpos) 5450 { 5451 pos_T *fp; 5452 list_T *l; 5453 int fnum = -1; 5454 5455 if (rettv_list_alloc(rettv) == OK) 5456 { 5457 l = rettv->vval.v_list; 5458 if (getcurpos) 5459 fp = &curwin->w_cursor; 5460 else 5461 fp = var2fpos(&argvars[0], TRUE, &fnum); 5462 if (fnum != -1) 5463 list_append_number(l, (varnumber_T)fnum); 5464 else 5465 list_append_number(l, (varnumber_T)0); 5466 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum 5467 : (varnumber_T)0); 5468 list_append_number(l, (fp != NULL) 5469 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1) 5470 : (varnumber_T)0); 5471 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd : 5472 (varnumber_T)0); 5473 if (getcurpos) 5474 { 5475 update_curswant(); 5476 list_append_number(l, curwin->w_curswant == MAXCOL ? 5477 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1); 5478 } 5479 } 5480 else 5481 rettv->vval.v_number = FALSE; 5482 } 5483 5484 /* 5485 * "getcurpos()" function 5486 */ 5487 static void 5488 f_getcurpos(typval_T *argvars, typval_T *rettv) 5489 { 5490 getpos_both(argvars, rettv, TRUE); 5491 } 5492 5493 /* 5494 * "getpos(string)" function 5495 */ 5496 static void 5497 f_getpos(typval_T *argvars, typval_T *rettv) 5498 { 5499 getpos_both(argvars, rettv, FALSE); 5500 } 5501 5502 /* 5503 * "getqflist()" function 5504 */ 5505 static void 5506 f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 5507 { 5508 #ifdef FEAT_QUICKFIX 5509 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv); 5510 #endif 5511 } 5512 5513 /* 5514 * "getreg()" function 5515 */ 5516 static void 5517 f_getreg(typval_T *argvars, typval_T *rettv) 5518 { 5519 char_u *strregname; 5520 int regname; 5521 int arg2 = FALSE; 5522 int return_list = FALSE; 5523 int error = FALSE; 5524 5525 if (argvars[0].v_type != VAR_UNKNOWN) 5526 { 5527 strregname = tv_get_string_chk(&argvars[0]); 5528 error = strregname == NULL; 5529 if (argvars[1].v_type != VAR_UNKNOWN) 5530 { 5531 arg2 = (int)tv_get_number_chk(&argvars[1], &error); 5532 if (!error && argvars[2].v_type != VAR_UNKNOWN) 5533 return_list = (int)tv_get_number_chk(&argvars[2], &error); 5534 } 5535 } 5536 else 5537 strregname = get_vim_var_str(VV_REG); 5538 5539 if (error) 5540 return; 5541 5542 regname = (strregname == NULL ? '"' : *strregname); 5543 if (regname == 0) 5544 regname = '"'; 5545 5546 if (return_list) 5547 { 5548 rettv->v_type = VAR_LIST; 5549 rettv->vval.v_list = (list_T *)get_reg_contents(regname, 5550 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST); 5551 if (rettv->vval.v_list == NULL) 5552 (void)rettv_list_alloc(rettv); 5553 else 5554 ++rettv->vval.v_list->lv_refcount; 5555 } 5556 else 5557 { 5558 rettv->v_type = VAR_STRING; 5559 rettv->vval.v_string = get_reg_contents(regname, 5560 arg2 ? GREG_EXPR_SRC : 0); 5561 } 5562 } 5563 5564 /* 5565 * "getregtype()" function 5566 */ 5567 static void 5568 f_getregtype(typval_T *argvars, typval_T *rettv) 5569 { 5570 char_u *strregname; 5571 int regname; 5572 char_u buf[NUMBUFLEN + 2]; 5573 long reglen = 0; 5574 5575 if (argvars[0].v_type != VAR_UNKNOWN) 5576 { 5577 strregname = tv_get_string_chk(&argvars[0]); 5578 if (strregname == NULL) /* type error; errmsg already given */ 5579 { 5580 rettv->v_type = VAR_STRING; 5581 rettv->vval.v_string = NULL; 5582 return; 5583 } 5584 } 5585 else 5586 /* Default to v:register */ 5587 strregname = get_vim_var_str(VV_REG); 5588 5589 regname = (strregname == NULL ? '"' : *strregname); 5590 if (regname == 0) 5591 regname = '"'; 5592 5593 buf[0] = NUL; 5594 buf[1] = NUL; 5595 switch (get_reg_type(regname, ®len)) 5596 { 5597 case MLINE: buf[0] = 'V'; break; 5598 case MCHAR: buf[0] = 'v'; break; 5599 case MBLOCK: 5600 buf[0] = Ctrl_V; 5601 sprintf((char *)buf + 1, "%ld", reglen + 1); 5602 break; 5603 } 5604 rettv->v_type = VAR_STRING; 5605 rettv->vval.v_string = vim_strsave(buf); 5606 } 5607 5608 /* 5609 * Returns information (variables, options, etc.) about a tab page 5610 * as a dictionary. 5611 */ 5612 static dict_T * 5613 get_tabpage_info(tabpage_T *tp, int tp_idx) 5614 { 5615 win_T *wp; 5616 dict_T *dict; 5617 list_T *l; 5618 5619 dict = dict_alloc(); 5620 if (dict == NULL) 5621 return NULL; 5622 5623 dict_add_number(dict, "tabnr", tp_idx); 5624 5625 l = list_alloc(); 5626 if (l != NULL) 5627 { 5628 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin; 5629 wp; wp = wp->w_next) 5630 list_append_number(l, (varnumber_T)wp->w_id); 5631 dict_add_list(dict, "windows", l); 5632 } 5633 5634 /* Make a reference to tabpage variables */ 5635 dict_add_dict(dict, "variables", tp->tp_vars); 5636 5637 return dict; 5638 } 5639 5640 /* 5641 * "gettabinfo()" function 5642 */ 5643 static void 5644 f_gettabinfo(typval_T *argvars, typval_T *rettv) 5645 { 5646 tabpage_T *tp, *tparg = NULL; 5647 dict_T *d; 5648 int tpnr = 0; 5649 5650 if (rettv_list_alloc(rettv) != OK) 5651 return; 5652 5653 if (argvars[0].v_type != VAR_UNKNOWN) 5654 { 5655 /* Information about one tab page */ 5656 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL)); 5657 if (tparg == NULL) 5658 return; 5659 } 5660 5661 /* Get information about a specific tab page or all tab pages */ 5662 FOR_ALL_TABPAGES(tp) 5663 { 5664 tpnr++; 5665 if (tparg != NULL && tp != tparg) 5666 continue; 5667 d = get_tabpage_info(tp, tpnr); 5668 if (d != NULL) 5669 list_append_dict(rettv->vval.v_list, d); 5670 if (tparg != NULL) 5671 return; 5672 } 5673 } 5674 5675 /* 5676 * "gettabvar()" function 5677 */ 5678 static void 5679 f_gettabvar(typval_T *argvars, typval_T *rettv) 5680 { 5681 win_T *oldcurwin; 5682 tabpage_T *tp, *oldtabpage; 5683 dictitem_T *v; 5684 char_u *varname; 5685 int done = FALSE; 5686 5687 rettv->v_type = VAR_STRING; 5688 rettv->vval.v_string = NULL; 5689 5690 varname = tv_get_string_chk(&argvars[1]); 5691 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL)); 5692 if (tp != NULL && varname != NULL) 5693 { 5694 /* Set tp to be our tabpage, temporarily. Also set the window to the 5695 * first window in the tabpage, otherwise the window is not valid. */ 5696 if (switch_win(&oldcurwin, &oldtabpage, 5697 tp == curtab || tp->tp_firstwin == NULL ? firstwin 5698 : tp->tp_firstwin, tp, TRUE) == OK) 5699 { 5700 /* look up the variable */ 5701 /* Let gettabvar({nr}, "") return the "t:" dictionary. */ 5702 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE); 5703 if (v != NULL) 5704 { 5705 copy_tv(&v->di_tv, rettv); 5706 done = TRUE; 5707 } 5708 } 5709 5710 /* restore previous notion of curwin */ 5711 restore_win(oldcurwin, oldtabpage, TRUE); 5712 } 5713 5714 if (!done && argvars[2].v_type != VAR_UNKNOWN) 5715 copy_tv(&argvars[2], rettv); 5716 } 5717 5718 /* 5719 * "gettabwinvar()" function 5720 */ 5721 static void 5722 f_gettabwinvar(typval_T *argvars, typval_T *rettv) 5723 { 5724 getwinvar(argvars, rettv, 1); 5725 } 5726 5727 /* 5728 * "gettagstack()" function 5729 */ 5730 static void 5731 f_gettagstack(typval_T *argvars, typval_T *rettv) 5732 { 5733 win_T *wp = curwin; // default is current window 5734 5735 if (rettv_dict_alloc(rettv) != OK) 5736 return; 5737 5738 if (argvars[0].v_type != VAR_UNKNOWN) 5739 { 5740 wp = find_win_by_nr_or_id(&argvars[0]); 5741 if (wp == NULL) 5742 return; 5743 } 5744 5745 get_tagstack(wp, rettv->vval.v_dict); 5746 } 5747 5748 /* 5749 * Returns information about a window as a dictionary. 5750 */ 5751 static dict_T * 5752 get_win_info(win_T *wp, short tpnr, short winnr) 5753 { 5754 dict_T *dict; 5755 5756 dict = dict_alloc(); 5757 if (dict == NULL) 5758 return NULL; 5759 5760 dict_add_number(dict, "tabnr", tpnr); 5761 dict_add_number(dict, "winnr", winnr); 5762 dict_add_number(dict, "winid", wp->w_id); 5763 dict_add_number(dict, "height", wp->w_height); 5764 dict_add_number(dict, "winrow", wp->w_winrow + 1); 5765 #ifdef FEAT_MENU 5766 dict_add_number(dict, "winbar", wp->w_winbar_height); 5767 #endif 5768 dict_add_number(dict, "width", wp->w_width); 5769 dict_add_number(dict, "wincol", wp->w_wincol + 1); 5770 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum); 5771 5772 #ifdef FEAT_TERMINAL 5773 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer)); 5774 #endif 5775 #ifdef FEAT_QUICKFIX 5776 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer)); 5777 dict_add_number(dict, "loclist", 5778 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL)); 5779 #endif 5780 5781 /* Add a reference to window variables */ 5782 dict_add_dict(dict, "variables", wp->w_vars); 5783 5784 return dict; 5785 } 5786 5787 /* 5788 * "getwininfo()" function 5789 */ 5790 static void 5791 f_getwininfo(typval_T *argvars, typval_T *rettv) 5792 { 5793 tabpage_T *tp; 5794 win_T *wp = NULL, *wparg = NULL; 5795 dict_T *d; 5796 short tabnr = 0, winnr; 5797 5798 if (rettv_list_alloc(rettv) != OK) 5799 return; 5800 5801 if (argvars[0].v_type != VAR_UNKNOWN) 5802 { 5803 wparg = win_id2wp(argvars); 5804 if (wparg == NULL) 5805 return; 5806 } 5807 5808 /* Collect information about either all the windows across all the tab 5809 * pages or one particular window. 5810 */ 5811 FOR_ALL_TABPAGES(tp) 5812 { 5813 tabnr++; 5814 winnr = 0; 5815 FOR_ALL_WINDOWS_IN_TAB(tp, wp) 5816 { 5817 winnr++; 5818 if (wparg != NULL && wp != wparg) 5819 continue; 5820 d = get_win_info(wp, tabnr, winnr); 5821 if (d != NULL) 5822 list_append_dict(rettv->vval.v_list, d); 5823 if (wparg != NULL) 5824 /* found information about a specific window */ 5825 return; 5826 } 5827 } 5828 } 5829 5830 /* 5831 * "win_findbuf()" function 5832 */ 5833 static void 5834 f_win_findbuf(typval_T *argvars, typval_T *rettv) 5835 { 5836 if (rettv_list_alloc(rettv) != FAIL) 5837 win_findbuf(argvars, rettv->vval.v_list); 5838 } 5839 5840 /* 5841 * "win_getid()" function 5842 */ 5843 static void 5844 f_win_getid(typval_T *argvars, typval_T *rettv) 5845 { 5846 rettv->vval.v_number = win_getid(argvars); 5847 } 5848 5849 /* 5850 * "win_gotoid()" function 5851 */ 5852 static void 5853 f_win_gotoid(typval_T *argvars, typval_T *rettv) 5854 { 5855 rettv->vval.v_number = win_gotoid(argvars); 5856 } 5857 5858 /* 5859 * "win_id2tabwin()" function 5860 */ 5861 static void 5862 f_win_id2tabwin(typval_T *argvars, typval_T *rettv) 5863 { 5864 if (rettv_list_alloc(rettv) != FAIL) 5865 win_id2tabwin(argvars, rettv->vval.v_list); 5866 } 5867 5868 /* 5869 * "win_id2win()" function 5870 */ 5871 static void 5872 f_win_id2win(typval_T *argvars, typval_T *rettv) 5873 { 5874 rettv->vval.v_number = win_id2win(argvars); 5875 } 5876 5877 /* 5878 * "win_screenpos()" function 5879 */ 5880 static void 5881 f_win_screenpos(typval_T *argvars, typval_T *rettv) 5882 { 5883 win_T *wp; 5884 5885 if (rettv_list_alloc(rettv) == FAIL) 5886 return; 5887 5888 wp = find_win_by_nr_or_id(&argvars[0]); 5889 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1); 5890 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1); 5891 } 5892 5893 /* 5894 * "getwinpos({timeout})" function 5895 */ 5896 static void 5897 f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv) 5898 { 5899 int x = -1; 5900 int y = -1; 5901 5902 if (rettv_list_alloc(rettv) == FAIL) 5903 return; 5904 #ifdef FEAT_GUI 5905 if (gui.in_use) 5906 (void)gui_mch_get_winpos(&x, &y); 5907 # if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE) 5908 else 5909 # endif 5910 #endif 5911 #if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE) 5912 { 5913 varnumber_T timeout = 100; 5914 5915 if (argvars[0].v_type != VAR_UNKNOWN) 5916 timeout = tv_get_number(&argvars[0]); 5917 term_get_winpos(&x, &y, timeout); 5918 } 5919 #endif 5920 list_append_number(rettv->vval.v_list, (varnumber_T)x); 5921 list_append_number(rettv->vval.v_list, (varnumber_T)y); 5922 } 5923 5924 5925 /* 5926 * "getwinposx()" function 5927 */ 5928 static void 5929 f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv) 5930 { 5931 rettv->vval.v_number = -1; 5932 #ifdef FEAT_GUI 5933 if (gui.in_use) 5934 { 5935 int x, y; 5936 5937 if (gui_mch_get_winpos(&x, &y) == OK) 5938 rettv->vval.v_number = x; 5939 return; 5940 } 5941 #endif 5942 #if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE) 5943 { 5944 int x, y; 5945 5946 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK) 5947 rettv->vval.v_number = x; 5948 } 5949 #endif 5950 } 5951 5952 /* 5953 * "getwinposy()" function 5954 */ 5955 static void 5956 f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv) 5957 { 5958 rettv->vval.v_number = -1; 5959 #ifdef FEAT_GUI 5960 if (gui.in_use) 5961 { 5962 int x, y; 5963 5964 if (gui_mch_get_winpos(&x, &y) == OK) 5965 rettv->vval.v_number = y; 5966 return; 5967 } 5968 #endif 5969 #if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE) 5970 { 5971 int x, y; 5972 5973 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK) 5974 rettv->vval.v_number = y; 5975 } 5976 #endif 5977 } 5978 5979 /* 5980 * "getwinvar()" function 5981 */ 5982 static void 5983 f_getwinvar(typval_T *argvars, typval_T *rettv) 5984 { 5985 getwinvar(argvars, rettv, 0); 5986 } 5987 5988 /* 5989 * "glob()" function 5990 */ 5991 static void 5992 f_glob(typval_T *argvars, typval_T *rettv) 5993 { 5994 int options = WILD_SILENT|WILD_USE_NL; 5995 expand_T xpc; 5996 int error = FALSE; 5997 5998 /* When the optional second argument is non-zero, don't remove matches 5999 * for 'wildignore' and don't put matches for 'suffixes' at the end. */ 6000 rettv->v_type = VAR_STRING; 6001 if (argvars[1].v_type != VAR_UNKNOWN) 6002 { 6003 if (tv_get_number_chk(&argvars[1], &error)) 6004 options |= WILD_KEEP_ALL; 6005 if (argvars[2].v_type != VAR_UNKNOWN) 6006 { 6007 if (tv_get_number_chk(&argvars[2], &error)) 6008 { 6009 rettv_list_set(rettv, NULL); 6010 } 6011 if (argvars[3].v_type != VAR_UNKNOWN 6012 && tv_get_number_chk(&argvars[3], &error)) 6013 options |= WILD_ALLLINKS; 6014 } 6015 } 6016 if (!error) 6017 { 6018 ExpandInit(&xpc); 6019 xpc.xp_context = EXPAND_FILES; 6020 if (p_wic) 6021 options += WILD_ICASE; 6022 if (rettv->v_type == VAR_STRING) 6023 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]), 6024 NULL, options, WILD_ALL); 6025 else if (rettv_list_alloc(rettv) != FAIL) 6026 { 6027 int i; 6028 6029 ExpandOne(&xpc, tv_get_string(&argvars[0]), 6030 NULL, options, WILD_ALL_KEEP); 6031 for (i = 0; i < xpc.xp_numfiles; i++) 6032 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); 6033 6034 ExpandCleanup(&xpc); 6035 } 6036 } 6037 else 6038 rettv->vval.v_string = NULL; 6039 } 6040 6041 /* 6042 * "globpath()" function 6043 */ 6044 static void 6045 f_globpath(typval_T *argvars, typval_T *rettv) 6046 { 6047 int flags = 0; 6048 char_u buf1[NUMBUFLEN]; 6049 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1); 6050 int error = FALSE; 6051 garray_T ga; 6052 int i; 6053 6054 /* When the optional second argument is non-zero, don't remove matches 6055 * for 'wildignore' and don't put matches for 'suffixes' at the end. */ 6056 rettv->v_type = VAR_STRING; 6057 if (argvars[2].v_type != VAR_UNKNOWN) 6058 { 6059 if (tv_get_number_chk(&argvars[2], &error)) 6060 flags |= WILD_KEEP_ALL; 6061 if (argvars[3].v_type != VAR_UNKNOWN) 6062 { 6063 if (tv_get_number_chk(&argvars[3], &error)) 6064 { 6065 rettv_list_set(rettv, NULL); 6066 } 6067 if (argvars[4].v_type != VAR_UNKNOWN 6068 && tv_get_number_chk(&argvars[4], &error)) 6069 flags |= WILD_ALLLINKS; 6070 } 6071 } 6072 if (file != NULL && !error) 6073 { 6074 ga_init2(&ga, (int)sizeof(char_u *), 10); 6075 globpath(tv_get_string(&argvars[0]), file, &ga, flags); 6076 if (rettv->v_type == VAR_STRING) 6077 rettv->vval.v_string = ga_concat_strings(&ga, "\n"); 6078 else if (rettv_list_alloc(rettv) != FAIL) 6079 for (i = 0; i < ga.ga_len; ++i) 6080 list_append_string(rettv->vval.v_list, 6081 ((char_u **)(ga.ga_data))[i], -1); 6082 ga_clear_strings(&ga); 6083 } 6084 else 6085 rettv->vval.v_string = NULL; 6086 } 6087 6088 /* 6089 * "glob2regpat()" function 6090 */ 6091 static void 6092 f_glob2regpat(typval_T *argvars, typval_T *rettv) 6093 { 6094 char_u *pat = tv_get_string_chk(&argvars[0]); 6095 6096 rettv->v_type = VAR_STRING; 6097 rettv->vval.v_string = (pat == NULL) 6098 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE); 6099 } 6100 6101 /* for VIM_VERSION_ defines */ 6102 #include "version.h" 6103 6104 /* 6105 * "has()" function 6106 */ 6107 static void 6108 f_has(typval_T *argvars, typval_T *rettv) 6109 { 6110 int i; 6111 char_u *name; 6112 int n = FALSE; 6113 static char *(has_list[]) = 6114 { 6115 #ifdef AMIGA 6116 "amiga", 6117 # ifdef FEAT_ARP 6118 "arp", 6119 # endif 6120 #endif 6121 #ifdef __BEOS__ 6122 "beos", 6123 #endif 6124 #if defined(BSD) && !defined(MACOS_X) 6125 "bsd", 6126 #endif 6127 #ifdef hpux 6128 "hpux", 6129 #endif 6130 #ifdef __linux__ 6131 "linux", 6132 #endif 6133 #ifdef MACOS_X 6134 "mac", /* Mac OS X (and, once, Mac OS Classic) */ 6135 "osx", /* Mac OS X */ 6136 # ifdef MACOS_X_DARWIN 6137 "macunix", /* Mac OS X, with the darwin feature */ 6138 "osxdarwin", /* synonym for macunix */ 6139 # endif 6140 #endif 6141 #ifdef __QNX__ 6142 "qnx", 6143 #endif 6144 #ifdef SUN_SYSTEM 6145 "sun", 6146 #else 6147 "moon", 6148 #endif 6149 #ifdef UNIX 6150 "unix", 6151 #endif 6152 #ifdef VMS 6153 "vms", 6154 #endif 6155 #ifdef WIN32 6156 "win32", 6157 #endif 6158 #if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__)) 6159 "win32unix", 6160 #endif 6161 #if defined(WIN64) || defined(_WIN64) 6162 "win64", 6163 #endif 6164 #ifdef EBCDIC 6165 "ebcdic", 6166 #endif 6167 #ifndef CASE_INSENSITIVE_FILENAME 6168 "fname_case", 6169 #endif 6170 #ifdef HAVE_ACL 6171 "acl", 6172 #endif 6173 #ifdef FEAT_ARABIC 6174 "arabic", 6175 #endif 6176 "autocmd", 6177 #ifdef FEAT_AUTOCHDIR 6178 "autochdir", 6179 #endif 6180 #ifdef FEAT_AUTOSERVERNAME 6181 "autoservername", 6182 #endif 6183 #ifdef FEAT_BEVAL_GUI 6184 "balloon_eval", 6185 # ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */ 6186 "balloon_multiline", 6187 # endif 6188 #endif 6189 #ifdef FEAT_BEVAL_TERM 6190 "balloon_eval_term", 6191 #endif 6192 #if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS) 6193 "builtin_terms", 6194 # ifdef ALL_BUILTIN_TCAPS 6195 "all_builtin_terms", 6196 # endif 6197 #endif 6198 #if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \ 6199 || defined(FEAT_GUI_W32) \ 6200 || defined(FEAT_GUI_MOTIF)) 6201 "browsefilter", 6202 #endif 6203 #ifdef FEAT_BYTEOFF 6204 "byte_offset", 6205 #endif 6206 #ifdef FEAT_JOB_CHANNEL 6207 "channel", 6208 #endif 6209 #ifdef FEAT_CINDENT 6210 "cindent", 6211 #endif 6212 #ifdef FEAT_CLIENTSERVER 6213 "clientserver", 6214 #endif 6215 #ifdef FEAT_CLIPBOARD 6216 "clipboard", 6217 #endif 6218 #ifdef FEAT_CMDL_COMPL 6219 "cmdline_compl", 6220 #endif 6221 #ifdef FEAT_CMDHIST 6222 "cmdline_hist", 6223 #endif 6224 #ifdef FEAT_COMMENTS 6225 "comments", 6226 #endif 6227 #ifdef FEAT_CONCEAL 6228 "conceal", 6229 #endif 6230 #ifdef FEAT_CRYPT 6231 "cryptv", 6232 "crypt-blowfish", 6233 "crypt-blowfish2", 6234 #endif 6235 #ifdef FEAT_CSCOPE 6236 "cscope", 6237 #endif 6238 "cursorbind", 6239 #ifdef CURSOR_SHAPE 6240 "cursorshape", 6241 #endif 6242 #ifdef DEBUG 6243 "debug", 6244 #endif 6245 #ifdef FEAT_CON_DIALOG 6246 "dialog_con", 6247 #endif 6248 #ifdef FEAT_GUI_DIALOG 6249 "dialog_gui", 6250 #endif 6251 #ifdef FEAT_DIFF 6252 "diff", 6253 #endif 6254 #ifdef FEAT_DIGRAPHS 6255 "digraphs", 6256 #endif 6257 #ifdef FEAT_DIRECTX 6258 "directx", 6259 #endif 6260 #ifdef FEAT_DND 6261 "dnd", 6262 #endif 6263 #ifdef FEAT_EMACS_TAGS 6264 "emacs_tags", 6265 #endif 6266 "eval", /* always present, of course! */ 6267 "ex_extra", /* graduated feature */ 6268 #ifdef FEAT_SEARCH_EXTRA 6269 "extra_search", 6270 #endif 6271 #ifdef FEAT_FKMAP 6272 "farsi", 6273 #endif 6274 #ifdef FEAT_SEARCHPATH 6275 "file_in_path", 6276 #endif 6277 #ifdef FEAT_FILTERPIPE 6278 "filterpipe", 6279 #endif 6280 #ifdef FEAT_FIND_ID 6281 "find_in_path", 6282 #endif 6283 #ifdef FEAT_FLOAT 6284 "float", 6285 #endif 6286 #ifdef FEAT_FOLDING 6287 "folding", 6288 #endif 6289 #ifdef FEAT_FOOTER 6290 "footer", 6291 #endif 6292 #if !defined(USE_SYSTEM) && defined(UNIX) 6293 "fork", 6294 #endif 6295 #ifdef FEAT_GETTEXT 6296 "gettext", 6297 #endif 6298 #ifdef FEAT_GUI 6299 "gui", 6300 #endif 6301 #ifdef FEAT_GUI_ATHENA 6302 # ifdef FEAT_GUI_NEXTAW 6303 "gui_neXtaw", 6304 # else 6305 "gui_athena", 6306 # endif 6307 #endif 6308 #ifdef FEAT_GUI_GTK 6309 "gui_gtk", 6310 # ifdef USE_GTK3 6311 "gui_gtk3", 6312 # else 6313 "gui_gtk2", 6314 # endif 6315 #endif 6316 #ifdef FEAT_GUI_GNOME 6317 "gui_gnome", 6318 #endif 6319 #ifdef FEAT_GUI_MAC 6320 "gui_mac", 6321 #endif 6322 #ifdef FEAT_GUI_MOTIF 6323 "gui_motif", 6324 #endif 6325 #ifdef FEAT_GUI_PHOTON 6326 "gui_photon", 6327 #endif 6328 #ifdef FEAT_GUI_W32 6329 "gui_win32", 6330 #endif 6331 #ifdef FEAT_HANGULIN 6332 "hangul_input", 6333 #endif 6334 #if defined(HAVE_ICONV_H) && defined(USE_ICONV) 6335 "iconv", 6336 #endif 6337 #ifdef FEAT_INS_EXPAND 6338 "insert_expand", 6339 #endif 6340 #ifdef FEAT_JOB_CHANNEL 6341 "job", 6342 #endif 6343 #ifdef FEAT_JUMPLIST 6344 "jumplist", 6345 #endif 6346 #ifdef FEAT_KEYMAP 6347 "keymap", 6348 #endif 6349 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */ 6350 #ifdef FEAT_LANGMAP 6351 "langmap", 6352 #endif 6353 #ifdef FEAT_LIBCALL 6354 "libcall", 6355 #endif 6356 #ifdef FEAT_LINEBREAK 6357 "linebreak", 6358 #endif 6359 #ifdef FEAT_LISP 6360 "lispindent", 6361 #endif 6362 "listcmds", 6363 #ifdef FEAT_LOCALMAP 6364 "localmap", 6365 #endif 6366 #ifdef FEAT_LUA 6367 # ifndef DYNAMIC_LUA 6368 "lua", 6369 # endif 6370 #endif 6371 #ifdef FEAT_MENU 6372 "menu", 6373 #endif 6374 #ifdef FEAT_SESSION 6375 "mksession", 6376 #endif 6377 #ifdef FEAT_MODIFY_FNAME 6378 "modify_fname", 6379 #endif 6380 #ifdef FEAT_MOUSE 6381 "mouse", 6382 #endif 6383 #ifdef FEAT_MOUSESHAPE 6384 "mouseshape", 6385 #endif 6386 #if defined(UNIX) || defined(VMS) 6387 # ifdef FEAT_MOUSE_DEC 6388 "mouse_dec", 6389 # endif 6390 # ifdef FEAT_MOUSE_GPM 6391 "mouse_gpm", 6392 # endif 6393 # ifdef FEAT_MOUSE_JSB 6394 "mouse_jsbterm", 6395 # endif 6396 # ifdef FEAT_MOUSE_NET 6397 "mouse_netterm", 6398 # endif 6399 # ifdef FEAT_MOUSE_PTERM 6400 "mouse_pterm", 6401 # endif 6402 # ifdef FEAT_MOUSE_SGR 6403 "mouse_sgr", 6404 # endif 6405 # ifdef FEAT_SYSMOUSE 6406 "mouse_sysmouse", 6407 # endif 6408 # ifdef FEAT_MOUSE_URXVT 6409 "mouse_urxvt", 6410 # endif 6411 # ifdef FEAT_MOUSE_XTERM 6412 "mouse_xterm", 6413 # endif 6414 #endif 6415 "multi_byte", 6416 #ifdef FEAT_MBYTE_IME 6417 "multi_byte_ime", 6418 #endif 6419 #ifdef FEAT_MULTI_LANG 6420 "multi_lang", 6421 #endif 6422 #ifdef FEAT_MZSCHEME 6423 #ifndef DYNAMIC_MZSCHEME 6424 "mzscheme", 6425 #endif 6426 #endif 6427 #ifdef FEAT_NUM64 6428 "num64", 6429 #endif 6430 #ifdef FEAT_OLE 6431 "ole", 6432 #endif 6433 #ifdef FEAT_EVAL 6434 "packages", 6435 #endif 6436 #ifdef FEAT_PATH_EXTRA 6437 "path_extra", 6438 #endif 6439 #ifdef FEAT_PERL 6440 #ifndef DYNAMIC_PERL 6441 "perl", 6442 #endif 6443 #endif 6444 #ifdef FEAT_PERSISTENT_UNDO 6445 "persistent_undo", 6446 #endif 6447 #if defined(FEAT_PYTHON) 6448 "python_compiled", 6449 # if defined(DYNAMIC_PYTHON) 6450 "python_dynamic", 6451 # else 6452 "python", 6453 "pythonx", 6454 # endif 6455 #endif 6456 #if defined(FEAT_PYTHON3) 6457 "python3_compiled", 6458 # if defined(DYNAMIC_PYTHON3) 6459 "python3_dynamic", 6460 # else 6461 "python3", 6462 "pythonx", 6463 # endif 6464 #endif 6465 #ifdef FEAT_POSTSCRIPT 6466 "postscript", 6467 #endif 6468 #ifdef FEAT_PRINTER 6469 "printer", 6470 #endif 6471 #ifdef FEAT_PROFILE 6472 "profile", 6473 #endif 6474 #ifdef FEAT_RELTIME 6475 "reltime", 6476 #endif 6477 #ifdef FEAT_QUICKFIX 6478 "quickfix", 6479 #endif 6480 #ifdef FEAT_RIGHTLEFT 6481 "rightleft", 6482 #endif 6483 #if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY) 6484 "ruby", 6485 #endif 6486 "scrollbind", 6487 #ifdef FEAT_CMDL_INFO 6488 "showcmd", 6489 "cmdline_info", 6490 #endif 6491 #ifdef FEAT_SIGNS 6492 "signs", 6493 #endif 6494 #ifdef FEAT_SMARTINDENT 6495 "smartindent", 6496 #endif 6497 #ifdef STARTUPTIME 6498 "startuptime", 6499 #endif 6500 #ifdef FEAT_STL_OPT 6501 "statusline", 6502 #endif 6503 #ifdef FEAT_NETBEANS_INTG 6504 "netbeans_intg", 6505 #endif 6506 #ifdef FEAT_SPELL 6507 "spell", 6508 #endif 6509 #ifdef FEAT_SYN_HL 6510 "syntax", 6511 #endif 6512 #if defined(USE_SYSTEM) || !defined(UNIX) 6513 "system", 6514 #endif 6515 #ifdef FEAT_TAG_BINS 6516 "tag_binary", 6517 #endif 6518 #ifdef FEAT_TAG_OLDSTATIC 6519 "tag_old_static", 6520 #endif 6521 #ifdef FEAT_TAG_ANYWHITE 6522 "tag_any_white", 6523 #endif 6524 #ifdef FEAT_TCL 6525 # ifndef DYNAMIC_TCL 6526 "tcl", 6527 # endif 6528 #endif 6529 #ifdef FEAT_TERMGUICOLORS 6530 "termguicolors", 6531 #endif 6532 #if defined(FEAT_TERMINAL) && !defined(WIN3264) 6533 "terminal", 6534 #endif 6535 #ifdef TERMINFO 6536 "terminfo", 6537 #endif 6538 #ifdef FEAT_TERMRESPONSE 6539 "termresponse", 6540 #endif 6541 #ifdef FEAT_TEXTOBJ 6542 "textobjects", 6543 #endif 6544 #ifdef FEAT_TEXT_PROP 6545 "textprop", 6546 #endif 6547 #ifdef HAVE_TGETENT 6548 "tgetent", 6549 #endif 6550 #ifdef FEAT_TIMERS 6551 "timers", 6552 #endif 6553 #ifdef FEAT_TITLE 6554 "title", 6555 #endif 6556 #ifdef FEAT_TOOLBAR 6557 "toolbar", 6558 #endif 6559 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11) 6560 "unnamedplus", 6561 #endif 6562 #ifdef FEAT_USR_CMDS 6563 "user-commands", /* was accidentally included in 5.4 */ 6564 "user_commands", 6565 #endif 6566 #ifdef FEAT_VARTABS 6567 "vartabs", 6568 #endif 6569 #ifdef FEAT_VIMINFO 6570 "viminfo", 6571 #endif 6572 "vertsplit", 6573 "virtualedit", 6574 "visual", 6575 "visualextra", 6576 "vreplace", 6577 #ifdef FEAT_VTP 6578 "vtp", 6579 #endif 6580 #ifdef FEAT_WILDIGN 6581 "wildignore", 6582 #endif 6583 #ifdef FEAT_WILDMENU 6584 "wildmenu", 6585 #endif 6586 "windows", 6587 #ifdef FEAT_WAK 6588 "winaltkeys", 6589 #endif 6590 #ifdef FEAT_WRITEBACKUP 6591 "writebackup", 6592 #endif 6593 #ifdef FEAT_XIM 6594 "xim", 6595 #endif 6596 #ifdef FEAT_XFONTSET 6597 "xfontset", 6598 #endif 6599 #ifdef FEAT_XPM_W32 6600 "xpm", 6601 "xpm_w32", /* for backward compatibility */ 6602 #else 6603 # if defined(HAVE_XPM) 6604 "xpm", 6605 # endif 6606 #endif 6607 #ifdef USE_XSMP 6608 "xsmp", 6609 #endif 6610 #ifdef USE_XSMP_INTERACT 6611 "xsmp_interact", 6612 #endif 6613 #ifdef FEAT_XCLIPBOARD 6614 "xterm_clipboard", 6615 #endif 6616 #ifdef FEAT_XTERM_SAVE 6617 "xterm_save", 6618 #endif 6619 #if defined(UNIX) && defined(FEAT_X11) 6620 "X11", 6621 #endif 6622 NULL 6623 }; 6624 6625 name = tv_get_string(&argvars[0]); 6626 for (i = 0; has_list[i] != NULL; ++i) 6627 if (STRICMP(name, has_list[i]) == 0) 6628 { 6629 n = TRUE; 6630 break; 6631 } 6632 6633 if (n == FALSE) 6634 { 6635 if (STRNICMP(name, "patch", 5) == 0) 6636 { 6637 if (name[5] == '-' 6638 && STRLEN(name) >= 11 6639 && vim_isdigit(name[6]) 6640 && vim_isdigit(name[8]) 6641 && vim_isdigit(name[10])) 6642 { 6643 int major = atoi((char *)name + 6); 6644 int minor = atoi((char *)name + 8); 6645 6646 /* Expect "patch-9.9.01234". */ 6647 n = (major < VIM_VERSION_MAJOR 6648 || (major == VIM_VERSION_MAJOR 6649 && (minor < VIM_VERSION_MINOR 6650 || (minor == VIM_VERSION_MINOR 6651 && has_patch(atoi((char *)name + 10)))))); 6652 } 6653 else 6654 n = has_patch(atoi((char *)name + 5)); 6655 } 6656 else if (STRICMP(name, "vim_starting") == 0) 6657 n = (starting != 0); 6658 else if (STRICMP(name, "ttyin") == 0) 6659 n = mch_input_isatty(); 6660 else if (STRICMP(name, "ttyout") == 0) 6661 n = stdout_isatty; 6662 else if (STRICMP(name, "multi_byte_encoding") == 0) 6663 n = has_mbyte; 6664 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32) 6665 else if (STRICMP(name, "balloon_multiline") == 0) 6666 n = multiline_balloon_available(); 6667 #endif 6668 #ifdef DYNAMIC_TCL 6669 else if (STRICMP(name, "tcl") == 0) 6670 n = tcl_enabled(FALSE); 6671 #endif 6672 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV) 6673 else if (STRICMP(name, "iconv") == 0) 6674 n = iconv_enabled(FALSE); 6675 #endif 6676 #ifdef DYNAMIC_LUA 6677 else if (STRICMP(name, "lua") == 0) 6678 n = lua_enabled(FALSE); 6679 #endif 6680 #ifdef DYNAMIC_MZSCHEME 6681 else if (STRICMP(name, "mzscheme") == 0) 6682 n = mzscheme_enabled(FALSE); 6683 #endif 6684 #ifdef DYNAMIC_RUBY 6685 else if (STRICMP(name, "ruby") == 0) 6686 n = ruby_enabled(FALSE); 6687 #endif 6688 #ifdef DYNAMIC_PYTHON 6689 else if (STRICMP(name, "python") == 0) 6690 n = python_enabled(FALSE); 6691 #endif 6692 #ifdef DYNAMIC_PYTHON3 6693 else if (STRICMP(name, "python3") == 0) 6694 n = python3_enabled(FALSE); 6695 #endif 6696 #if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3) 6697 else if (STRICMP(name, "pythonx") == 0) 6698 { 6699 # if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3) 6700 if (p_pyx == 0) 6701 n = python3_enabled(FALSE) || python_enabled(FALSE); 6702 else if (p_pyx == 3) 6703 n = python3_enabled(FALSE); 6704 else if (p_pyx == 2) 6705 n = python_enabled(FALSE); 6706 # elif defined(DYNAMIC_PYTHON) 6707 n = python_enabled(FALSE); 6708 # elif defined(DYNAMIC_PYTHON3) 6709 n = python3_enabled(FALSE); 6710 # endif 6711 } 6712 #endif 6713 #ifdef DYNAMIC_PERL 6714 else if (STRICMP(name, "perl") == 0) 6715 n = perl_enabled(FALSE); 6716 #endif 6717 #ifdef FEAT_GUI 6718 else if (STRICMP(name, "gui_running") == 0) 6719 n = (gui.in_use || gui.starting); 6720 # ifdef FEAT_BROWSE 6721 else if (STRICMP(name, "browse") == 0) 6722 n = gui.in_use; /* gui_mch_browse() works when GUI is running */ 6723 # endif 6724 #endif 6725 #ifdef FEAT_SYN_HL 6726 else if (STRICMP(name, "syntax_items") == 0) 6727 n = syntax_present(curwin); 6728 #endif 6729 #ifdef FEAT_VTP 6730 else if (STRICMP(name, "vcon") == 0) 6731 n = is_term_win32() && has_vtp_working(); 6732 #endif 6733 #ifdef FEAT_NETBEANS_INTG 6734 else if (STRICMP(name, "netbeans_enabled") == 0) 6735 n = netbeans_active(); 6736 #endif 6737 #if defined(FEAT_TERMINAL) && defined(WIN3264) 6738 else if (STRICMP(name, "terminal") == 0) 6739 n = terminal_enabled(); 6740 #endif 6741 #if defined(FEAT_TERMINAL) && defined(WIN3264) 6742 else if (STRICMP(name, "conpty") == 0) 6743 n = use_conpty(); 6744 #endif 6745 } 6746 6747 rettv->vval.v_number = n; 6748 } 6749 6750 /* 6751 * "has_key()" function 6752 */ 6753 static void 6754 f_has_key(typval_T *argvars, typval_T *rettv) 6755 { 6756 if (argvars[0].v_type != VAR_DICT) 6757 { 6758 emsg(_(e_dictreq)); 6759 return; 6760 } 6761 if (argvars[0].vval.v_dict == NULL) 6762 return; 6763 6764 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict, 6765 tv_get_string(&argvars[1]), -1) != NULL; 6766 } 6767 6768 /* 6769 * "haslocaldir()" function 6770 */ 6771 static void 6772 f_haslocaldir(typval_T *argvars, typval_T *rettv) 6773 { 6774 win_T *wp = NULL; 6775 6776 wp = find_tabwin(&argvars[0], &argvars[1]); 6777 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL); 6778 } 6779 6780 /* 6781 * "hasmapto()" function 6782 */ 6783 static void 6784 f_hasmapto(typval_T *argvars, typval_T *rettv) 6785 { 6786 char_u *name; 6787 char_u *mode; 6788 char_u buf[NUMBUFLEN]; 6789 int abbr = FALSE; 6790 6791 name = tv_get_string(&argvars[0]); 6792 if (argvars[1].v_type == VAR_UNKNOWN) 6793 mode = (char_u *)"nvo"; 6794 else 6795 { 6796 mode = tv_get_string_buf(&argvars[1], buf); 6797 if (argvars[2].v_type != VAR_UNKNOWN) 6798 abbr = (int)tv_get_number(&argvars[2]); 6799 } 6800 6801 if (map_to_exists(name, mode, abbr)) 6802 rettv->vval.v_number = TRUE; 6803 else 6804 rettv->vval.v_number = FALSE; 6805 } 6806 6807 /* 6808 * "histadd()" function 6809 */ 6810 static void 6811 f_histadd(typval_T *argvars UNUSED, typval_T *rettv) 6812 { 6813 #ifdef FEAT_CMDHIST 6814 int histype; 6815 char_u *str; 6816 char_u buf[NUMBUFLEN]; 6817 #endif 6818 6819 rettv->vval.v_number = FALSE; 6820 if (check_restricted() || check_secure()) 6821 return; 6822 #ifdef FEAT_CMDHIST 6823 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */ 6824 histype = str != NULL ? get_histtype(str) : -1; 6825 if (histype >= 0) 6826 { 6827 str = tv_get_string_buf(&argvars[1], buf); 6828 if (*str != NUL) 6829 { 6830 init_history(); 6831 add_to_history(histype, str, FALSE, NUL); 6832 rettv->vval.v_number = TRUE; 6833 return; 6834 } 6835 } 6836 #endif 6837 } 6838 6839 /* 6840 * "histdel()" function 6841 */ 6842 static void 6843 f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 6844 { 6845 #ifdef FEAT_CMDHIST 6846 int n; 6847 char_u buf[NUMBUFLEN]; 6848 char_u *str; 6849 6850 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */ 6851 if (str == NULL) 6852 n = 0; 6853 else if (argvars[1].v_type == VAR_UNKNOWN) 6854 /* only one argument: clear entire history */ 6855 n = clr_history(get_histtype(str)); 6856 else if (argvars[1].v_type == VAR_NUMBER) 6857 /* index given: remove that entry */ 6858 n = del_history_idx(get_histtype(str), 6859 (int)tv_get_number(&argvars[1])); 6860 else 6861 /* string given: remove all matching entries */ 6862 n = del_history_entry(get_histtype(str), 6863 tv_get_string_buf(&argvars[1], buf)); 6864 rettv->vval.v_number = n; 6865 #endif 6866 } 6867 6868 /* 6869 * "histget()" function 6870 */ 6871 static void 6872 f_histget(typval_T *argvars UNUSED, typval_T *rettv) 6873 { 6874 #ifdef FEAT_CMDHIST 6875 int type; 6876 int idx; 6877 char_u *str; 6878 6879 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */ 6880 if (str == NULL) 6881 rettv->vval.v_string = NULL; 6882 else 6883 { 6884 type = get_histtype(str); 6885 if (argvars[1].v_type == VAR_UNKNOWN) 6886 idx = get_history_idx(type); 6887 else 6888 idx = (int)tv_get_number_chk(&argvars[1], NULL); 6889 /* -1 on type error */ 6890 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx)); 6891 } 6892 #else 6893 rettv->vval.v_string = NULL; 6894 #endif 6895 rettv->v_type = VAR_STRING; 6896 } 6897 6898 /* 6899 * "histnr()" function 6900 */ 6901 static void 6902 f_histnr(typval_T *argvars UNUSED, typval_T *rettv) 6903 { 6904 int i; 6905 6906 #ifdef FEAT_CMDHIST 6907 char_u *history = tv_get_string_chk(&argvars[0]); 6908 6909 i = history == NULL ? HIST_CMD - 1 : get_histtype(history); 6910 if (i >= HIST_CMD && i < HIST_COUNT) 6911 i = get_history_idx(i); 6912 else 6913 #endif 6914 i = -1; 6915 rettv->vval.v_number = i; 6916 } 6917 6918 /* 6919 * "highlightID(name)" function 6920 */ 6921 static void 6922 f_hlID(typval_T *argvars, typval_T *rettv) 6923 { 6924 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0])); 6925 } 6926 6927 /* 6928 * "highlight_exists()" function 6929 */ 6930 static void 6931 f_hlexists(typval_T *argvars, typval_T *rettv) 6932 { 6933 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0])); 6934 } 6935 6936 /* 6937 * "hostname()" function 6938 */ 6939 static void 6940 f_hostname(typval_T *argvars UNUSED, typval_T *rettv) 6941 { 6942 char_u hostname[256]; 6943 6944 mch_get_host_name(hostname, 256); 6945 rettv->v_type = VAR_STRING; 6946 rettv->vval.v_string = vim_strsave(hostname); 6947 } 6948 6949 /* 6950 * iconv() function 6951 */ 6952 static void 6953 f_iconv(typval_T *argvars UNUSED, typval_T *rettv) 6954 { 6955 char_u buf1[NUMBUFLEN]; 6956 char_u buf2[NUMBUFLEN]; 6957 char_u *from, *to, *str; 6958 vimconv_T vimconv; 6959 6960 rettv->v_type = VAR_STRING; 6961 rettv->vval.v_string = NULL; 6962 6963 str = tv_get_string(&argvars[0]); 6964 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1))); 6965 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2))); 6966 vimconv.vc_type = CONV_NONE; 6967 convert_setup(&vimconv, from, to); 6968 6969 /* If the encodings are equal, no conversion needed. */ 6970 if (vimconv.vc_type == CONV_NONE) 6971 rettv->vval.v_string = vim_strsave(str); 6972 else 6973 rettv->vval.v_string = string_convert(&vimconv, str, NULL); 6974 6975 convert_setup(&vimconv, NULL, NULL); 6976 vim_free(from); 6977 vim_free(to); 6978 } 6979 6980 /* 6981 * "indent()" function 6982 */ 6983 static void 6984 f_indent(typval_T *argvars, typval_T *rettv) 6985 { 6986 linenr_T lnum; 6987 6988 lnum = tv_get_lnum(argvars); 6989 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) 6990 rettv->vval.v_number = get_indent_lnum(lnum); 6991 else 6992 rettv->vval.v_number = -1; 6993 } 6994 6995 /* 6996 * "index()" function 6997 */ 6998 static void 6999 f_index(typval_T *argvars, typval_T *rettv) 7000 { 7001 list_T *l; 7002 listitem_T *item; 7003 blob_T *b; 7004 long idx = 0; 7005 int ic = FALSE; 7006 int error = FALSE; 7007 7008 rettv->vval.v_number = -1; 7009 if (argvars[0].v_type == VAR_BLOB) 7010 { 7011 typval_T tv; 7012 int start = 0; 7013 7014 if (argvars[2].v_type != VAR_UNKNOWN) 7015 { 7016 start = tv_get_number_chk(&argvars[2], &error); 7017 if (error) 7018 return; 7019 } 7020 b = argvars[0].vval.v_blob; 7021 if (b == NULL) 7022 return; 7023 if (start < 0) 7024 { 7025 start = blob_len(b) + start; 7026 if (start < 0) 7027 start = 0; 7028 } 7029 7030 for (idx = start; idx < blob_len(b); ++idx) 7031 { 7032 tv.v_type = VAR_NUMBER; 7033 tv.vval.v_number = blob_get(b, idx); 7034 if (tv_equal(&tv, &argvars[1], ic, FALSE)) 7035 { 7036 rettv->vval.v_number = idx; 7037 return; 7038 } 7039 } 7040 return; 7041 } 7042 else if (argvars[0].v_type != VAR_LIST) 7043 { 7044 emsg(_(e_listblobreq)); 7045 return; 7046 } 7047 7048 l = argvars[0].vval.v_list; 7049 if (l != NULL) 7050 { 7051 item = l->lv_first; 7052 if (argvars[2].v_type != VAR_UNKNOWN) 7053 { 7054 /* Start at specified item. Use the cached index that list_find() 7055 * sets, so that a negative number also works. */ 7056 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error)); 7057 idx = l->lv_idx; 7058 if (argvars[3].v_type != VAR_UNKNOWN) 7059 ic = (int)tv_get_number_chk(&argvars[3], &error); 7060 if (error) 7061 item = NULL; 7062 } 7063 7064 for ( ; item != NULL; item = item->li_next, ++idx) 7065 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE)) 7066 { 7067 rettv->vval.v_number = idx; 7068 break; 7069 } 7070 } 7071 } 7072 7073 static int inputsecret_flag = 0; 7074 7075 /* 7076 * "input()" function 7077 * Also handles inputsecret() when inputsecret is set. 7078 */ 7079 static void 7080 f_input(typval_T *argvars, typval_T *rettv) 7081 { 7082 get_user_input(argvars, rettv, FALSE, inputsecret_flag); 7083 } 7084 7085 /* 7086 * "inputdialog()" function 7087 */ 7088 static void 7089 f_inputdialog(typval_T *argvars, typval_T *rettv) 7090 { 7091 #if defined(FEAT_GUI_TEXTDIALOG) 7092 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */ 7093 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL) 7094 { 7095 char_u *message; 7096 char_u buf[NUMBUFLEN]; 7097 char_u *defstr = (char_u *)""; 7098 7099 message = tv_get_string_chk(&argvars[0]); 7100 if (argvars[1].v_type != VAR_UNKNOWN 7101 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL) 7102 vim_strncpy(IObuff, defstr, IOSIZE - 1); 7103 else 7104 IObuff[0] = NUL; 7105 if (message != NULL && defstr != NULL 7106 && do_dialog(VIM_QUESTION, NULL, message, 7107 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1) 7108 rettv->vval.v_string = vim_strsave(IObuff); 7109 else 7110 { 7111 if (message != NULL && defstr != NULL 7112 && argvars[1].v_type != VAR_UNKNOWN 7113 && argvars[2].v_type != VAR_UNKNOWN) 7114 rettv->vval.v_string = vim_strsave( 7115 tv_get_string_buf(&argvars[2], buf)); 7116 else 7117 rettv->vval.v_string = NULL; 7118 } 7119 rettv->v_type = VAR_STRING; 7120 } 7121 else 7122 #endif 7123 get_user_input(argvars, rettv, TRUE, inputsecret_flag); 7124 } 7125 7126 /* 7127 * "inputlist()" function 7128 */ 7129 static void 7130 f_inputlist(typval_T *argvars, typval_T *rettv) 7131 { 7132 listitem_T *li; 7133 int selected; 7134 int mouse_used; 7135 7136 #ifdef NO_CONSOLE_INPUT 7137 /* While starting up, there is no place to enter text. When running tests 7138 * with --not-a-term we assume feedkeys() will be used. */ 7139 if (no_console_input() && !is_not_a_term()) 7140 return; 7141 #endif 7142 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL) 7143 { 7144 semsg(_(e_listarg), "inputlist()"); 7145 return; 7146 } 7147 7148 msg_start(); 7149 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */ 7150 lines_left = Rows; /* avoid more prompt */ 7151 msg_scroll = TRUE; 7152 msg_clr_eos(); 7153 7154 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next) 7155 { 7156 msg_puts((char *)tv_get_string(&li->li_tv)); 7157 msg_putchar('\n'); 7158 } 7159 7160 /* Ask for choice. */ 7161 selected = prompt_for_number(&mouse_used); 7162 if (mouse_used) 7163 selected -= lines_left; 7164 7165 rettv->vval.v_number = selected; 7166 } 7167 7168 static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL}; 7169 7170 /* 7171 * "inputrestore()" function 7172 */ 7173 static void 7174 f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv) 7175 { 7176 if (ga_userinput.ga_len > 0) 7177 { 7178 --ga_userinput.ga_len; 7179 restore_typeahead((tasave_T *)(ga_userinput.ga_data) 7180 + ga_userinput.ga_len); 7181 /* default return is zero == OK */ 7182 } 7183 else if (p_verbose > 1) 7184 { 7185 verb_msg(_("called inputrestore() more often than inputsave()")); 7186 rettv->vval.v_number = 1; /* Failed */ 7187 } 7188 } 7189 7190 /* 7191 * "inputsave()" function 7192 */ 7193 static void 7194 f_inputsave(typval_T *argvars UNUSED, typval_T *rettv) 7195 { 7196 /* Add an entry to the stack of typeahead storage. */ 7197 if (ga_grow(&ga_userinput, 1) == OK) 7198 { 7199 save_typeahead((tasave_T *)(ga_userinput.ga_data) 7200 + ga_userinput.ga_len); 7201 ++ga_userinput.ga_len; 7202 /* default return is zero == OK */ 7203 } 7204 else 7205 rettv->vval.v_number = 1; /* Failed */ 7206 } 7207 7208 /* 7209 * "inputsecret()" function 7210 */ 7211 static void 7212 f_inputsecret(typval_T *argvars, typval_T *rettv) 7213 { 7214 ++cmdline_star; 7215 ++inputsecret_flag; 7216 f_input(argvars, rettv); 7217 --cmdline_star; 7218 --inputsecret_flag; 7219 } 7220 7221 /* 7222 * "insert()" function 7223 */ 7224 static void 7225 f_insert(typval_T *argvars, typval_T *rettv) 7226 { 7227 long before = 0; 7228 listitem_T *item; 7229 list_T *l; 7230 int error = FALSE; 7231 7232 if (argvars[0].v_type == VAR_BLOB) 7233 { 7234 int val, len; 7235 char_u *p; 7236 7237 len = blob_len(argvars[0].vval.v_blob); 7238 if (argvars[2].v_type != VAR_UNKNOWN) 7239 { 7240 before = (long)tv_get_number_chk(&argvars[2], &error); 7241 if (error) 7242 return; // type error; errmsg already given 7243 if (before < 0 || before > len) 7244 { 7245 semsg(_(e_invarg2), tv_get_string(&argvars[2])); 7246 return; 7247 } 7248 } 7249 val = tv_get_number_chk(&argvars[1], &error); 7250 if (error) 7251 return; 7252 if (val < 0 || val > 255) 7253 { 7254 semsg(_(e_invarg2), tv_get_string(&argvars[1])); 7255 return; 7256 } 7257 7258 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL) 7259 return; 7260 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data; 7261 mch_memmove(p + before + 1, p + before, (size_t)len - before); 7262 *(p + before) = val; 7263 ++argvars[0].vval.v_blob->bv_ga.ga_len; 7264 7265 copy_tv(&argvars[0], rettv); 7266 } 7267 else if (argvars[0].v_type != VAR_LIST) 7268 semsg(_(e_listblobarg), "insert()"); 7269 else if ((l = argvars[0].vval.v_list) != NULL && !tv_check_lock(l->lv_lock, 7270 (char_u *)N_("insert() argument"), TRUE)) 7271 { 7272 if (argvars[2].v_type != VAR_UNKNOWN) 7273 before = (long)tv_get_number_chk(&argvars[2], &error); 7274 if (error) 7275 return; /* type error; errmsg already given */ 7276 7277 if (before == l->lv_len) 7278 item = NULL; 7279 else 7280 { 7281 item = list_find(l, before); 7282 if (item == NULL) 7283 { 7284 semsg(_(e_listidx), before); 7285 l = NULL; 7286 } 7287 } 7288 if (l != NULL) 7289 { 7290 list_insert_tv(l, &argvars[1], item); 7291 copy_tv(&argvars[0], rettv); 7292 } 7293 } 7294 } 7295 7296 /* 7297 * "invert(expr)" function 7298 */ 7299 static void 7300 f_invert(typval_T *argvars, typval_T *rettv) 7301 { 7302 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL); 7303 } 7304 7305 /* 7306 * "isdirectory()" function 7307 */ 7308 static void 7309 f_isdirectory(typval_T *argvars, typval_T *rettv) 7310 { 7311 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0])); 7312 } 7313 7314 /* 7315 * Return TRUE if typeval "tv" is locked: Either that value is locked itself 7316 * or it refers to a List or Dictionary that is locked. 7317 */ 7318 static int 7319 tv_islocked(typval_T *tv) 7320 { 7321 return (tv->v_lock & VAR_LOCKED) 7322 || (tv->v_type == VAR_LIST 7323 && tv->vval.v_list != NULL 7324 && (tv->vval.v_list->lv_lock & VAR_LOCKED)) 7325 || (tv->v_type == VAR_DICT 7326 && tv->vval.v_dict != NULL 7327 && (tv->vval.v_dict->dv_lock & VAR_LOCKED)); 7328 } 7329 7330 /* 7331 * "islocked()" function 7332 */ 7333 static void 7334 f_islocked(typval_T *argvars, typval_T *rettv) 7335 { 7336 lval_T lv; 7337 char_u *end; 7338 dictitem_T *di; 7339 7340 rettv->vval.v_number = -1; 7341 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE, 7342 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START); 7343 if (end != NULL && lv.ll_name != NULL) 7344 { 7345 if (*end != NUL) 7346 emsg(_(e_trailing)); 7347 else 7348 { 7349 if (lv.ll_tv == NULL) 7350 { 7351 di = find_var(lv.ll_name, NULL, TRUE); 7352 if (di != NULL) 7353 { 7354 /* Consider a variable locked when: 7355 * 1. the variable itself is locked 7356 * 2. the value of the variable is locked. 7357 * 3. the List or Dict value is locked. 7358 */ 7359 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK) 7360 || tv_islocked(&di->di_tv)); 7361 } 7362 } 7363 else if (lv.ll_range) 7364 emsg(_("E786: Range not allowed")); 7365 else if (lv.ll_newkey != NULL) 7366 semsg(_(e_dictkey), lv.ll_newkey); 7367 else if (lv.ll_list != NULL) 7368 /* List item. */ 7369 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv); 7370 else 7371 /* Dictionary item. */ 7372 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv); 7373 } 7374 } 7375 7376 clear_lval(&lv); 7377 } 7378 7379 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) 7380 /* 7381 * "isnan()" function 7382 */ 7383 static void 7384 f_isnan(typval_T *argvars, typval_T *rettv) 7385 { 7386 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT 7387 && isnan(argvars[0].vval.v_float); 7388 } 7389 #endif 7390 7391 /* 7392 * "items(dict)" function 7393 */ 7394 static void 7395 f_items(typval_T *argvars, typval_T *rettv) 7396 { 7397 dict_list(argvars, rettv, 2); 7398 } 7399 7400 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) 7401 /* 7402 * Get the job from the argument. 7403 * Returns NULL if the job is invalid. 7404 */ 7405 static job_T * 7406 get_job_arg(typval_T *tv) 7407 { 7408 job_T *job; 7409 7410 if (tv->v_type != VAR_JOB) 7411 { 7412 semsg(_(e_invarg2), tv_get_string(tv)); 7413 return NULL; 7414 } 7415 job = tv->vval.v_job; 7416 7417 if (job == NULL) 7418 emsg(_("E916: not a valid job")); 7419 return job; 7420 } 7421 7422 /* 7423 * "job_getchannel()" function 7424 */ 7425 static void 7426 f_job_getchannel(typval_T *argvars, typval_T *rettv) 7427 { 7428 job_T *job = get_job_arg(&argvars[0]); 7429 7430 if (job != NULL) 7431 { 7432 rettv->v_type = VAR_CHANNEL; 7433 rettv->vval.v_channel = job->jv_channel; 7434 if (job->jv_channel != NULL) 7435 ++job->jv_channel->ch_refcount; 7436 } 7437 } 7438 7439 /* 7440 * "job_info()" function 7441 */ 7442 static void 7443 f_job_info(typval_T *argvars, typval_T *rettv) 7444 { 7445 if (argvars[0].v_type != VAR_UNKNOWN) 7446 { 7447 job_T *job = get_job_arg(&argvars[0]); 7448 7449 if (job != NULL && rettv_dict_alloc(rettv) != FAIL) 7450 job_info(job, rettv->vval.v_dict); 7451 } 7452 else if (rettv_list_alloc(rettv) == OK) 7453 job_info_all(rettv->vval.v_list); 7454 } 7455 7456 /* 7457 * "job_setoptions()" function 7458 */ 7459 static void 7460 f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED) 7461 { 7462 job_T *job = get_job_arg(&argvars[0]); 7463 jobopt_T opt; 7464 7465 if (job == NULL) 7466 return; 7467 clear_job_options(&opt); 7468 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK) 7469 job_set_options(job, &opt); 7470 free_job_options(&opt); 7471 } 7472 7473 /* 7474 * "job_start()" function 7475 */ 7476 static void 7477 f_job_start(typval_T *argvars, typval_T *rettv) 7478 { 7479 rettv->v_type = VAR_JOB; 7480 if (check_restricted() || check_secure()) 7481 return; 7482 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE); 7483 } 7484 7485 /* 7486 * "job_status()" function 7487 */ 7488 static void 7489 f_job_status(typval_T *argvars, typval_T *rettv) 7490 { 7491 job_T *job = get_job_arg(&argvars[0]); 7492 7493 if (job != NULL) 7494 { 7495 rettv->v_type = VAR_STRING; 7496 rettv->vval.v_string = vim_strsave((char_u *)job_status(job)); 7497 } 7498 } 7499 7500 /* 7501 * "job_stop()" function 7502 */ 7503 static void 7504 f_job_stop(typval_T *argvars, typval_T *rettv) 7505 { 7506 job_T *job = get_job_arg(&argvars[0]); 7507 7508 if (job != NULL) 7509 rettv->vval.v_number = job_stop(job, argvars, NULL); 7510 } 7511 #endif 7512 7513 /* 7514 * "join()" function 7515 */ 7516 static void 7517 f_join(typval_T *argvars, typval_T *rettv) 7518 { 7519 garray_T ga; 7520 char_u *sep; 7521 7522 if (argvars[0].v_type != VAR_LIST) 7523 { 7524 emsg(_(e_listreq)); 7525 return; 7526 } 7527 if (argvars[0].vval.v_list == NULL) 7528 return; 7529 if (argvars[1].v_type == VAR_UNKNOWN) 7530 sep = (char_u *)" "; 7531 else 7532 sep = tv_get_string_chk(&argvars[1]); 7533 7534 rettv->v_type = VAR_STRING; 7535 7536 if (sep != NULL) 7537 { 7538 ga_init2(&ga, (int)sizeof(char), 80); 7539 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0); 7540 ga_append(&ga, NUL); 7541 rettv->vval.v_string = (char_u *)ga.ga_data; 7542 } 7543 else 7544 rettv->vval.v_string = NULL; 7545 } 7546 7547 /* 7548 * "js_decode()" function 7549 */ 7550 static void 7551 f_js_decode(typval_T *argvars, typval_T *rettv) 7552 { 7553 js_read_T reader; 7554 7555 reader.js_buf = tv_get_string(&argvars[0]); 7556 reader.js_fill = NULL; 7557 reader.js_used = 0; 7558 if (json_decode_all(&reader, rettv, JSON_JS) != OK) 7559 emsg(_(e_invarg)); 7560 } 7561 7562 /* 7563 * "js_encode()" function 7564 */ 7565 static void 7566 f_js_encode(typval_T *argvars, typval_T *rettv) 7567 { 7568 rettv->v_type = VAR_STRING; 7569 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS); 7570 } 7571 7572 /* 7573 * "json_decode()" function 7574 */ 7575 static void 7576 f_json_decode(typval_T *argvars, typval_T *rettv) 7577 { 7578 js_read_T reader; 7579 7580 reader.js_buf = tv_get_string(&argvars[0]); 7581 reader.js_fill = NULL; 7582 reader.js_used = 0; 7583 json_decode_all(&reader, rettv, 0); 7584 } 7585 7586 /* 7587 * "json_encode()" function 7588 */ 7589 static void 7590 f_json_encode(typval_T *argvars, typval_T *rettv) 7591 { 7592 rettv->v_type = VAR_STRING; 7593 rettv->vval.v_string = json_encode(&argvars[0], 0); 7594 } 7595 7596 /* 7597 * "keys()" function 7598 */ 7599 static void 7600 f_keys(typval_T *argvars, typval_T *rettv) 7601 { 7602 dict_list(argvars, rettv, 0); 7603 } 7604 7605 /* 7606 * "last_buffer_nr()" function. 7607 */ 7608 static void 7609 f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv) 7610 { 7611 int n = 0; 7612 buf_T *buf; 7613 7614 FOR_ALL_BUFFERS(buf) 7615 if (n < buf->b_fnum) 7616 n = buf->b_fnum; 7617 7618 rettv->vval.v_number = n; 7619 } 7620 7621 /* 7622 * "len()" function 7623 */ 7624 static void 7625 f_len(typval_T *argvars, typval_T *rettv) 7626 { 7627 switch (argvars[0].v_type) 7628 { 7629 case VAR_STRING: 7630 case VAR_NUMBER: 7631 rettv->vval.v_number = (varnumber_T)STRLEN( 7632 tv_get_string(&argvars[0])); 7633 break; 7634 case VAR_BLOB: 7635 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob); 7636 break; 7637 case VAR_LIST: 7638 rettv->vval.v_number = list_len(argvars[0].vval.v_list); 7639 break; 7640 case VAR_DICT: 7641 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict); 7642 break; 7643 case VAR_UNKNOWN: 7644 case VAR_SPECIAL: 7645 case VAR_FLOAT: 7646 case VAR_FUNC: 7647 case VAR_PARTIAL: 7648 case VAR_JOB: 7649 case VAR_CHANNEL: 7650 emsg(_("E701: Invalid type for len()")); 7651 break; 7652 } 7653 } 7654 7655 static void 7656 libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type) 7657 { 7658 #ifdef FEAT_LIBCALL 7659 char_u *string_in; 7660 char_u **string_result; 7661 int nr_result; 7662 #endif 7663 7664 rettv->v_type = type; 7665 if (type != VAR_NUMBER) 7666 rettv->vval.v_string = NULL; 7667 7668 if (check_restricted() || check_secure()) 7669 return; 7670 7671 #ifdef FEAT_LIBCALL 7672 /* The first two args must be strings, otherwise it's meaningless */ 7673 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING) 7674 { 7675 string_in = NULL; 7676 if (argvars[2].v_type == VAR_STRING) 7677 string_in = argvars[2].vval.v_string; 7678 if (type == VAR_NUMBER) 7679 string_result = NULL; 7680 else 7681 string_result = &rettv->vval.v_string; 7682 if (mch_libcall(argvars[0].vval.v_string, 7683 argvars[1].vval.v_string, 7684 string_in, 7685 argvars[2].vval.v_number, 7686 string_result, 7687 &nr_result) == OK 7688 && type == VAR_NUMBER) 7689 rettv->vval.v_number = nr_result; 7690 } 7691 #endif 7692 } 7693 7694 /* 7695 * "libcall()" function 7696 */ 7697 static void 7698 f_libcall(typval_T *argvars, typval_T *rettv) 7699 { 7700 libcall_common(argvars, rettv, VAR_STRING); 7701 } 7702 7703 /* 7704 * "libcallnr()" function 7705 */ 7706 static void 7707 f_libcallnr(typval_T *argvars, typval_T *rettv) 7708 { 7709 libcall_common(argvars, rettv, VAR_NUMBER); 7710 } 7711 7712 /* 7713 * "line(string)" function 7714 */ 7715 static void 7716 f_line(typval_T *argvars, typval_T *rettv) 7717 { 7718 linenr_T lnum = 0; 7719 pos_T *fp; 7720 int fnum; 7721 7722 fp = var2fpos(&argvars[0], TRUE, &fnum); 7723 if (fp != NULL) 7724 lnum = fp->lnum; 7725 rettv->vval.v_number = lnum; 7726 } 7727 7728 /* 7729 * "line2byte(lnum)" function 7730 */ 7731 static void 7732 f_line2byte(typval_T *argvars UNUSED, typval_T *rettv) 7733 { 7734 #ifndef FEAT_BYTEOFF 7735 rettv->vval.v_number = -1; 7736 #else 7737 linenr_T lnum; 7738 7739 lnum = tv_get_lnum(argvars); 7740 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) 7741 rettv->vval.v_number = -1; 7742 else 7743 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL); 7744 if (rettv->vval.v_number >= 0) 7745 ++rettv->vval.v_number; 7746 #endif 7747 } 7748 7749 /* 7750 * "lispindent(lnum)" function 7751 */ 7752 static void 7753 f_lispindent(typval_T *argvars UNUSED, typval_T *rettv) 7754 { 7755 #ifdef FEAT_LISP 7756 pos_T pos; 7757 linenr_T lnum; 7758 7759 pos = curwin->w_cursor; 7760 lnum = tv_get_lnum(argvars); 7761 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) 7762 { 7763 curwin->w_cursor.lnum = lnum; 7764 rettv->vval.v_number = get_lisp_indent(); 7765 curwin->w_cursor = pos; 7766 } 7767 else 7768 #endif 7769 rettv->vval.v_number = -1; 7770 } 7771 7772 /* 7773 * "localtime()" function 7774 */ 7775 static void 7776 f_localtime(typval_T *argvars UNUSED, typval_T *rettv) 7777 { 7778 rettv->vval.v_number = (varnumber_T)time(NULL); 7779 } 7780 7781 static void 7782 get_maparg(typval_T *argvars, typval_T *rettv, int exact) 7783 { 7784 char_u *keys; 7785 char_u *which; 7786 char_u buf[NUMBUFLEN]; 7787 char_u *keys_buf = NULL; 7788 char_u *rhs; 7789 int mode; 7790 int abbr = FALSE; 7791 int get_dict = FALSE; 7792 mapblock_T *mp; 7793 int buffer_local; 7794 7795 /* return empty string for failure */ 7796 rettv->v_type = VAR_STRING; 7797 rettv->vval.v_string = NULL; 7798 7799 keys = tv_get_string(&argvars[0]); 7800 if (*keys == NUL) 7801 return; 7802 7803 if (argvars[1].v_type != VAR_UNKNOWN) 7804 { 7805 which = tv_get_string_buf_chk(&argvars[1], buf); 7806 if (argvars[2].v_type != VAR_UNKNOWN) 7807 { 7808 abbr = (int)tv_get_number(&argvars[2]); 7809 if (argvars[3].v_type != VAR_UNKNOWN) 7810 get_dict = (int)tv_get_number(&argvars[3]); 7811 } 7812 } 7813 else 7814 which = (char_u *)""; 7815 if (which == NULL) 7816 return; 7817 7818 mode = get_map_mode(&which, 0); 7819 7820 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE); 7821 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local); 7822 vim_free(keys_buf); 7823 7824 if (!get_dict) 7825 { 7826 /* Return a string. */ 7827 if (rhs != NULL) 7828 { 7829 if (*rhs == NUL) 7830 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>"); 7831 else 7832 rettv->vval.v_string = str2special_save(rhs, FALSE); 7833 } 7834 7835 } 7836 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL) 7837 { 7838 /* Return a dictionary. */ 7839 char_u *lhs = str2special_save(mp->m_keys, TRUE); 7840 char_u *mapmode = map_mode_to_chars(mp->m_mode); 7841 dict_T *dict = rettv->vval.v_dict; 7842 7843 dict_add_string(dict, "lhs", lhs); 7844 dict_add_string(dict, "rhs", mp->m_orig_str); 7845 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L); 7846 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L); 7847 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L); 7848 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid); 7849 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum); 7850 dict_add_number(dict, "buffer", (long)buffer_local); 7851 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L); 7852 dict_add_string(dict, "mode", mapmode); 7853 7854 vim_free(lhs); 7855 vim_free(mapmode); 7856 } 7857 } 7858 7859 #ifdef FEAT_FLOAT 7860 /* 7861 * "log()" function 7862 */ 7863 static void 7864 f_log(typval_T *argvars, typval_T *rettv) 7865 { 7866 float_T f = 0.0; 7867 7868 rettv->v_type = VAR_FLOAT; 7869 if (get_float_arg(argvars, &f) == OK) 7870 rettv->vval.v_float = log(f); 7871 else 7872 rettv->vval.v_float = 0.0; 7873 } 7874 7875 /* 7876 * "log10()" function 7877 */ 7878 static void 7879 f_log10(typval_T *argvars, typval_T *rettv) 7880 { 7881 float_T f = 0.0; 7882 7883 rettv->v_type = VAR_FLOAT; 7884 if (get_float_arg(argvars, &f) == OK) 7885 rettv->vval.v_float = log10(f); 7886 else 7887 rettv->vval.v_float = 0.0; 7888 } 7889 #endif 7890 7891 #ifdef FEAT_LUA 7892 /* 7893 * "luaeval()" function 7894 */ 7895 static void 7896 f_luaeval(typval_T *argvars, typval_T *rettv) 7897 { 7898 char_u *str; 7899 char_u buf[NUMBUFLEN]; 7900 7901 str = tv_get_string_buf(&argvars[0], buf); 7902 do_luaeval(str, argvars + 1, rettv); 7903 } 7904 #endif 7905 7906 /* 7907 * "map()" function 7908 */ 7909 static void 7910 f_map(typval_T *argvars, typval_T *rettv) 7911 { 7912 filter_map(argvars, rettv, TRUE); 7913 } 7914 7915 /* 7916 * "maparg()" function 7917 */ 7918 static void 7919 f_maparg(typval_T *argvars, typval_T *rettv) 7920 { 7921 get_maparg(argvars, rettv, TRUE); 7922 } 7923 7924 /* 7925 * "mapcheck()" function 7926 */ 7927 static void 7928 f_mapcheck(typval_T *argvars, typval_T *rettv) 7929 { 7930 get_maparg(argvars, rettv, FALSE); 7931 } 7932 7933 typedef enum 7934 { 7935 MATCH_END, /* matchend() */ 7936 MATCH_MATCH, /* match() */ 7937 MATCH_STR, /* matchstr() */ 7938 MATCH_LIST, /* matchlist() */ 7939 MATCH_POS /* matchstrpos() */ 7940 } matchtype_T; 7941 7942 static void 7943 find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type) 7944 { 7945 char_u *str = NULL; 7946 long len = 0; 7947 char_u *expr = NULL; 7948 char_u *pat; 7949 regmatch_T regmatch; 7950 char_u patbuf[NUMBUFLEN]; 7951 char_u strbuf[NUMBUFLEN]; 7952 char_u *save_cpo; 7953 long start = 0; 7954 long nth = 1; 7955 colnr_T startcol = 0; 7956 int match = 0; 7957 list_T *l = NULL; 7958 listitem_T *li = NULL; 7959 long idx = 0; 7960 char_u *tofree = NULL; 7961 7962 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ 7963 save_cpo = p_cpo; 7964 p_cpo = (char_u *)""; 7965 7966 rettv->vval.v_number = -1; 7967 if (type == MATCH_LIST || type == MATCH_POS) 7968 { 7969 /* type MATCH_LIST: return empty list when there are no matches. 7970 * type MATCH_POS: return ["", -1, -1, -1] */ 7971 if (rettv_list_alloc(rettv) == FAIL) 7972 goto theend; 7973 if (type == MATCH_POS 7974 && (list_append_string(rettv->vval.v_list, 7975 (char_u *)"", 0) == FAIL 7976 || list_append_number(rettv->vval.v_list, 7977 (varnumber_T)-1) == FAIL 7978 || list_append_number(rettv->vval.v_list, 7979 (varnumber_T)-1) == FAIL 7980 || list_append_number(rettv->vval.v_list, 7981 (varnumber_T)-1) == FAIL)) 7982 { 7983 list_free(rettv->vval.v_list); 7984 rettv->vval.v_list = NULL; 7985 goto theend; 7986 } 7987 } 7988 else if (type == MATCH_STR) 7989 { 7990 rettv->v_type = VAR_STRING; 7991 rettv->vval.v_string = NULL; 7992 } 7993 7994 if (argvars[0].v_type == VAR_LIST) 7995 { 7996 if ((l = argvars[0].vval.v_list) == NULL) 7997 goto theend; 7998 li = l->lv_first; 7999 } 8000 else 8001 { 8002 expr = str = tv_get_string(&argvars[0]); 8003 len = (long)STRLEN(str); 8004 } 8005 8006 pat = tv_get_string_buf_chk(&argvars[1], patbuf); 8007 if (pat == NULL) 8008 goto theend; 8009 8010 if (argvars[2].v_type != VAR_UNKNOWN) 8011 { 8012 int error = FALSE; 8013 8014 start = (long)tv_get_number_chk(&argvars[2], &error); 8015 if (error) 8016 goto theend; 8017 if (l != NULL) 8018 { 8019 li = list_find(l, start); 8020 if (li == NULL) 8021 goto theend; 8022 idx = l->lv_idx; /* use the cached index */ 8023 } 8024 else 8025 { 8026 if (start < 0) 8027 start = 0; 8028 if (start > len) 8029 goto theend; 8030 /* When "count" argument is there ignore matches before "start", 8031 * otherwise skip part of the string. Differs when pattern is "^" 8032 * or "\<". */ 8033 if (argvars[3].v_type != VAR_UNKNOWN) 8034 startcol = start; 8035 else 8036 { 8037 str += start; 8038 len -= start; 8039 } 8040 } 8041 8042 if (argvars[3].v_type != VAR_UNKNOWN) 8043 nth = (long)tv_get_number_chk(&argvars[3], &error); 8044 if (error) 8045 goto theend; 8046 } 8047 8048 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); 8049 if (regmatch.regprog != NULL) 8050 { 8051 regmatch.rm_ic = p_ic; 8052 8053 for (;;) 8054 { 8055 if (l != NULL) 8056 { 8057 if (li == NULL) 8058 { 8059 match = FALSE; 8060 break; 8061 } 8062 vim_free(tofree); 8063 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0); 8064 if (str == NULL) 8065 break; 8066 } 8067 8068 match = vim_regexec_nl(®match, str, (colnr_T)startcol); 8069 8070 if (match && --nth <= 0) 8071 break; 8072 if (l == NULL && !match) 8073 break; 8074 8075 /* Advance to just after the match. */ 8076 if (l != NULL) 8077 { 8078 li = li->li_next; 8079 ++idx; 8080 } 8081 else 8082 { 8083 startcol = (colnr_T)(regmatch.startp[0] 8084 + (*mb_ptr2len)(regmatch.startp[0]) - str); 8085 if (startcol > (colnr_T)len 8086 || str + startcol <= regmatch.startp[0]) 8087 { 8088 match = FALSE; 8089 break; 8090 } 8091 } 8092 } 8093 8094 if (match) 8095 { 8096 if (type == MATCH_POS) 8097 { 8098 listitem_T *li1 = rettv->vval.v_list->lv_first; 8099 listitem_T *li2 = li1->li_next; 8100 listitem_T *li3 = li2->li_next; 8101 listitem_T *li4 = li3->li_next; 8102 8103 vim_free(li1->li_tv.vval.v_string); 8104 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0], 8105 (int)(regmatch.endp[0] - regmatch.startp[0])); 8106 li3->li_tv.vval.v_number = 8107 (varnumber_T)(regmatch.startp[0] - expr); 8108 li4->li_tv.vval.v_number = 8109 (varnumber_T)(regmatch.endp[0] - expr); 8110 if (l != NULL) 8111 li2->li_tv.vval.v_number = (varnumber_T)idx; 8112 } 8113 else if (type == MATCH_LIST) 8114 { 8115 int i; 8116 8117 /* return list with matched string and submatches */ 8118 for (i = 0; i < NSUBEXP; ++i) 8119 { 8120 if (regmatch.endp[i] == NULL) 8121 { 8122 if (list_append_string(rettv->vval.v_list, 8123 (char_u *)"", 0) == FAIL) 8124 break; 8125 } 8126 else if (list_append_string(rettv->vval.v_list, 8127 regmatch.startp[i], 8128 (int)(regmatch.endp[i] - regmatch.startp[i])) 8129 == FAIL) 8130 break; 8131 } 8132 } 8133 else if (type == MATCH_STR) 8134 { 8135 /* return matched string */ 8136 if (l != NULL) 8137 copy_tv(&li->li_tv, rettv); 8138 else 8139 rettv->vval.v_string = vim_strnsave(regmatch.startp[0], 8140 (int)(regmatch.endp[0] - regmatch.startp[0])); 8141 } 8142 else if (l != NULL) 8143 rettv->vval.v_number = idx; 8144 else 8145 { 8146 if (type != MATCH_END) 8147 rettv->vval.v_number = 8148 (varnumber_T)(regmatch.startp[0] - str); 8149 else 8150 rettv->vval.v_number = 8151 (varnumber_T)(regmatch.endp[0] - str); 8152 rettv->vval.v_number += (varnumber_T)(str - expr); 8153 } 8154 } 8155 vim_regfree(regmatch.regprog); 8156 } 8157 8158 theend: 8159 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL) 8160 /* matchstrpos() without a list: drop the second item. */ 8161 listitem_remove(rettv->vval.v_list, 8162 rettv->vval.v_list->lv_first->li_next); 8163 vim_free(tofree); 8164 p_cpo = save_cpo; 8165 } 8166 8167 /* 8168 * "match()" function 8169 */ 8170 static void 8171 f_match(typval_T *argvars, typval_T *rettv) 8172 { 8173 find_some_match(argvars, rettv, MATCH_MATCH); 8174 } 8175 8176 #ifdef FEAT_SEARCH_EXTRA 8177 static int 8178 matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win) 8179 { 8180 dictitem_T *di; 8181 8182 if (tv->v_type != VAR_DICT) 8183 { 8184 emsg(_(e_dictreq)); 8185 return FAIL; 8186 } 8187 8188 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL) 8189 *conceal_char = dict_get_string(tv->vval.v_dict, 8190 (char_u *)"conceal", FALSE); 8191 8192 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL) 8193 { 8194 *win = find_win_by_nr_or_id(&di->di_tv); 8195 if (*win == NULL) 8196 { 8197 emsg(_("E957: Invalid window number")); 8198 return FAIL; 8199 } 8200 } 8201 8202 return OK; 8203 } 8204 #endif 8205 8206 /* 8207 * "matchadd()" function 8208 */ 8209 static void 8210 f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 8211 { 8212 #ifdef FEAT_SEARCH_EXTRA 8213 char_u buf[NUMBUFLEN]; 8214 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */ 8215 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */ 8216 int prio = 10; /* default priority */ 8217 int id = -1; 8218 int error = FALSE; 8219 char_u *conceal_char = NULL; 8220 win_T *win = curwin; 8221 8222 rettv->vval.v_number = -1; 8223 8224 if (grp == NULL || pat == NULL) 8225 return; 8226 if (argvars[2].v_type != VAR_UNKNOWN) 8227 { 8228 prio = (int)tv_get_number_chk(&argvars[2], &error); 8229 if (argvars[3].v_type != VAR_UNKNOWN) 8230 { 8231 id = (int)tv_get_number_chk(&argvars[3], &error); 8232 if (argvars[4].v_type != VAR_UNKNOWN 8233 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL) 8234 return; 8235 } 8236 } 8237 if (error == TRUE) 8238 return; 8239 if (id >= 1 && id <= 3) 8240 { 8241 semsg(_("E798: ID is reserved for \":match\": %d"), id); 8242 return; 8243 } 8244 8245 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL, 8246 conceal_char); 8247 #endif 8248 } 8249 8250 /* 8251 * "matchaddpos()" function 8252 */ 8253 static void 8254 f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 8255 { 8256 #ifdef FEAT_SEARCH_EXTRA 8257 char_u buf[NUMBUFLEN]; 8258 char_u *group; 8259 int prio = 10; 8260 int id = -1; 8261 int error = FALSE; 8262 list_T *l; 8263 char_u *conceal_char = NULL; 8264 win_T *win = curwin; 8265 8266 rettv->vval.v_number = -1; 8267 8268 group = tv_get_string_buf_chk(&argvars[0], buf); 8269 if (group == NULL) 8270 return; 8271 8272 if (argvars[1].v_type != VAR_LIST) 8273 { 8274 semsg(_(e_listarg), "matchaddpos()"); 8275 return; 8276 } 8277 l = argvars[1].vval.v_list; 8278 if (l == NULL) 8279 return; 8280 8281 if (argvars[2].v_type != VAR_UNKNOWN) 8282 { 8283 prio = (int)tv_get_number_chk(&argvars[2], &error); 8284 if (argvars[3].v_type != VAR_UNKNOWN) 8285 { 8286 id = (int)tv_get_number_chk(&argvars[3], &error); 8287 8288 if (argvars[4].v_type != VAR_UNKNOWN 8289 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL) 8290 return; 8291 } 8292 } 8293 if (error == TRUE) 8294 return; 8295 8296 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */ 8297 if (id == 1 || id == 2) 8298 { 8299 semsg(_("E798: ID is reserved for \":match\": %d"), id); 8300 return; 8301 } 8302 8303 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l, 8304 conceal_char); 8305 #endif 8306 } 8307 8308 /* 8309 * "matcharg()" function 8310 */ 8311 static void 8312 f_matcharg(typval_T *argvars UNUSED, typval_T *rettv) 8313 { 8314 if (rettv_list_alloc(rettv) == OK) 8315 { 8316 #ifdef FEAT_SEARCH_EXTRA 8317 int id = (int)tv_get_number(&argvars[0]); 8318 matchitem_T *m; 8319 8320 if (id >= 1 && id <= 3) 8321 { 8322 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL) 8323 { 8324 list_append_string(rettv->vval.v_list, 8325 syn_id2name(m->hlg_id), -1); 8326 list_append_string(rettv->vval.v_list, m->pattern, -1); 8327 } 8328 else 8329 { 8330 list_append_string(rettv->vval.v_list, NULL, -1); 8331 list_append_string(rettv->vval.v_list, NULL, -1); 8332 } 8333 } 8334 #endif 8335 } 8336 } 8337 8338 /* 8339 * "matchdelete()" function 8340 */ 8341 static void 8342 f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 8343 { 8344 #ifdef FEAT_SEARCH_EXTRA 8345 rettv->vval.v_number = match_delete(curwin, 8346 (int)tv_get_number(&argvars[0]), TRUE); 8347 #endif 8348 } 8349 8350 /* 8351 * "matchend()" function 8352 */ 8353 static void 8354 f_matchend(typval_T *argvars, typval_T *rettv) 8355 { 8356 find_some_match(argvars, rettv, MATCH_END); 8357 } 8358 8359 /* 8360 * "matchlist()" function 8361 */ 8362 static void 8363 f_matchlist(typval_T *argvars, typval_T *rettv) 8364 { 8365 find_some_match(argvars, rettv, MATCH_LIST); 8366 } 8367 8368 /* 8369 * "matchstr()" function 8370 */ 8371 static void 8372 f_matchstr(typval_T *argvars, typval_T *rettv) 8373 { 8374 find_some_match(argvars, rettv, MATCH_STR); 8375 } 8376 8377 /* 8378 * "matchstrpos()" function 8379 */ 8380 static void 8381 f_matchstrpos(typval_T *argvars, typval_T *rettv) 8382 { 8383 find_some_match(argvars, rettv, MATCH_POS); 8384 } 8385 8386 static void 8387 max_min(typval_T *argvars, typval_T *rettv, int domax) 8388 { 8389 varnumber_T n = 0; 8390 varnumber_T i; 8391 int error = FALSE; 8392 8393 if (argvars[0].v_type == VAR_LIST) 8394 { 8395 list_T *l; 8396 listitem_T *li; 8397 8398 l = argvars[0].vval.v_list; 8399 if (l != NULL) 8400 { 8401 li = l->lv_first; 8402 if (li != NULL) 8403 { 8404 n = tv_get_number_chk(&li->li_tv, &error); 8405 for (;;) 8406 { 8407 li = li->li_next; 8408 if (li == NULL) 8409 break; 8410 i = tv_get_number_chk(&li->li_tv, &error); 8411 if (domax ? i > n : i < n) 8412 n = i; 8413 } 8414 } 8415 } 8416 } 8417 else if (argvars[0].v_type == VAR_DICT) 8418 { 8419 dict_T *d; 8420 int first = TRUE; 8421 hashitem_T *hi; 8422 int todo; 8423 8424 d = argvars[0].vval.v_dict; 8425 if (d != NULL) 8426 { 8427 todo = (int)d->dv_hashtab.ht_used; 8428 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) 8429 { 8430 if (!HASHITEM_EMPTY(hi)) 8431 { 8432 --todo; 8433 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error); 8434 if (first) 8435 { 8436 n = i; 8437 first = FALSE; 8438 } 8439 else if (domax ? i > n : i < n) 8440 n = i; 8441 } 8442 } 8443 } 8444 } 8445 else 8446 semsg(_(e_listdictarg), domax ? "max()" : "min()"); 8447 rettv->vval.v_number = error ? 0 : n; 8448 } 8449 8450 /* 8451 * "max()" function 8452 */ 8453 static void 8454 f_max(typval_T *argvars, typval_T *rettv) 8455 { 8456 max_min(argvars, rettv, TRUE); 8457 } 8458 8459 /* 8460 * "min()" function 8461 */ 8462 static void 8463 f_min(typval_T *argvars, typval_T *rettv) 8464 { 8465 max_min(argvars, rettv, FALSE); 8466 } 8467 8468 /* 8469 * Create the directory in which "dir" is located, and higher levels when 8470 * needed. 8471 * Return OK or FAIL. 8472 */ 8473 static int 8474 mkdir_recurse(char_u *dir, int prot) 8475 { 8476 char_u *p; 8477 char_u *updir; 8478 int r = FAIL; 8479 8480 /* Get end of directory name in "dir". 8481 * We're done when it's "/" or "c:/". */ 8482 p = gettail_sep(dir); 8483 if (p <= get_past_head(dir)) 8484 return OK; 8485 8486 /* If the directory exists we're done. Otherwise: create it.*/ 8487 updir = vim_strnsave(dir, (int)(p - dir)); 8488 if (updir == NULL) 8489 return FAIL; 8490 if (mch_isdir(updir)) 8491 r = OK; 8492 else if (mkdir_recurse(updir, prot) == OK) 8493 r = vim_mkdir_emsg(updir, prot); 8494 vim_free(updir); 8495 return r; 8496 } 8497 8498 #ifdef vim_mkdir 8499 /* 8500 * "mkdir()" function 8501 */ 8502 static void 8503 f_mkdir(typval_T *argvars, typval_T *rettv) 8504 { 8505 char_u *dir; 8506 char_u buf[NUMBUFLEN]; 8507 int prot = 0755; 8508 8509 rettv->vval.v_number = FAIL; 8510 if (check_restricted() || check_secure()) 8511 return; 8512 8513 dir = tv_get_string_buf(&argvars[0], buf); 8514 if (*dir == NUL) 8515 return; 8516 8517 if (*gettail(dir) == NUL) 8518 /* remove trailing slashes */ 8519 *gettail_sep(dir) = NUL; 8520 8521 if (argvars[1].v_type != VAR_UNKNOWN) 8522 { 8523 if (argvars[2].v_type != VAR_UNKNOWN) 8524 { 8525 prot = (int)tv_get_number_chk(&argvars[2], NULL); 8526 if (prot == -1) 8527 return; 8528 } 8529 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0) 8530 { 8531 if (mch_isdir(dir)) 8532 { 8533 /* With the "p" flag it's OK if the dir already exists. */ 8534 rettv->vval.v_number = OK; 8535 return; 8536 } 8537 mkdir_recurse(dir, prot); 8538 } 8539 } 8540 rettv->vval.v_number = vim_mkdir_emsg(dir, prot); 8541 } 8542 #endif 8543 8544 /* 8545 * "mode()" function 8546 */ 8547 static void 8548 f_mode(typval_T *argvars, typval_T *rettv) 8549 { 8550 char_u buf[4]; 8551 8552 vim_memset(buf, 0, sizeof(buf)); 8553 8554 if (time_for_testing == 93784) 8555 { 8556 /* Testing the two-character code. */ 8557 buf[0] = 'x'; 8558 buf[1] = '!'; 8559 } 8560 #ifdef FEAT_TERMINAL 8561 else if (term_use_loop()) 8562 buf[0] = 't'; 8563 #endif 8564 else if (VIsual_active) 8565 { 8566 if (VIsual_select) 8567 buf[0] = VIsual_mode + 's' - 'v'; 8568 else 8569 buf[0] = VIsual_mode; 8570 } 8571 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE 8572 || State == CONFIRM) 8573 { 8574 buf[0] = 'r'; 8575 if (State == ASKMORE) 8576 buf[1] = 'm'; 8577 else if (State == CONFIRM) 8578 buf[1] = '?'; 8579 } 8580 else if (State == EXTERNCMD) 8581 buf[0] = '!'; 8582 else if (State & INSERT) 8583 { 8584 if (State & VREPLACE_FLAG) 8585 { 8586 buf[0] = 'R'; 8587 buf[1] = 'v'; 8588 } 8589 else 8590 { 8591 if (State & REPLACE_FLAG) 8592 buf[0] = 'R'; 8593 else 8594 buf[0] = 'i'; 8595 #ifdef FEAT_INS_EXPAND 8596 if (ins_compl_active()) 8597 buf[1] = 'c'; 8598 else if (ctrl_x_mode_not_defined_yet()) 8599 buf[1] = 'x'; 8600 #endif 8601 } 8602 } 8603 else if ((State & CMDLINE) || exmode_active) 8604 { 8605 buf[0] = 'c'; 8606 if (exmode_active == EXMODE_VIM) 8607 buf[1] = 'v'; 8608 else if (exmode_active == EXMODE_NORMAL) 8609 buf[1] = 'e'; 8610 } 8611 else 8612 { 8613 buf[0] = 'n'; 8614 if (finish_op) 8615 { 8616 buf[1] = 'o'; 8617 // to be able to detect force-linewise/blockwise/characterwise operations 8618 buf[2] = motion_force; 8619 } 8620 else if (restart_edit == 'I' || restart_edit == 'R' 8621 || restart_edit == 'V') 8622 { 8623 buf[1] = 'i'; 8624 buf[2] = restart_edit; 8625 } 8626 } 8627 8628 /* Clear out the minor mode when the argument is not a non-zero number or 8629 * non-empty string. */ 8630 if (!non_zero_arg(&argvars[0])) 8631 buf[1] = NUL; 8632 8633 rettv->vval.v_string = vim_strsave(buf); 8634 rettv->v_type = VAR_STRING; 8635 } 8636 8637 #if defined(FEAT_MZSCHEME) || defined(PROTO) 8638 /* 8639 * "mzeval()" function 8640 */ 8641 static void 8642 f_mzeval(typval_T *argvars, typval_T *rettv) 8643 { 8644 char_u *str; 8645 char_u buf[NUMBUFLEN]; 8646 8647 str = tv_get_string_buf(&argvars[0], buf); 8648 do_mzeval(str, rettv); 8649 } 8650 8651 void 8652 mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv) 8653 { 8654 typval_T argvars[3]; 8655 8656 argvars[0].v_type = VAR_STRING; 8657 argvars[0].vval.v_string = name; 8658 copy_tv(args, &argvars[1]); 8659 argvars[2].v_type = VAR_UNKNOWN; 8660 f_call(argvars, rettv); 8661 clear_tv(&argvars[1]); 8662 } 8663 #endif 8664 8665 /* 8666 * "nextnonblank()" function 8667 */ 8668 static void 8669 f_nextnonblank(typval_T *argvars, typval_T *rettv) 8670 { 8671 linenr_T lnum; 8672 8673 for (lnum = tv_get_lnum(argvars); ; ++lnum) 8674 { 8675 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count) 8676 { 8677 lnum = 0; 8678 break; 8679 } 8680 if (*skipwhite(ml_get(lnum)) != NUL) 8681 break; 8682 } 8683 rettv->vval.v_number = lnum; 8684 } 8685 8686 /* 8687 * "nr2char()" function 8688 */ 8689 static void 8690 f_nr2char(typval_T *argvars, typval_T *rettv) 8691 { 8692 char_u buf[NUMBUFLEN]; 8693 8694 if (has_mbyte) 8695 { 8696 int utf8 = 0; 8697 8698 if (argvars[1].v_type != VAR_UNKNOWN) 8699 utf8 = (int)tv_get_number_chk(&argvars[1], NULL); 8700 if (utf8) 8701 buf[(*utf_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL; 8702 else 8703 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL; 8704 } 8705 else 8706 { 8707 buf[0] = (char_u)tv_get_number(&argvars[0]); 8708 buf[1] = NUL; 8709 } 8710 rettv->v_type = VAR_STRING; 8711 rettv->vval.v_string = vim_strsave(buf); 8712 } 8713 8714 /* 8715 * "or(expr, expr)" function 8716 */ 8717 static void 8718 f_or(typval_T *argvars, typval_T *rettv) 8719 { 8720 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL) 8721 | tv_get_number_chk(&argvars[1], NULL); 8722 } 8723 8724 /* 8725 * "pathshorten()" function 8726 */ 8727 static void 8728 f_pathshorten(typval_T *argvars, typval_T *rettv) 8729 { 8730 char_u *p; 8731 8732 rettv->v_type = VAR_STRING; 8733 p = tv_get_string_chk(&argvars[0]); 8734 if (p == NULL) 8735 rettv->vval.v_string = NULL; 8736 else 8737 { 8738 p = vim_strsave(p); 8739 rettv->vval.v_string = p; 8740 if (p != NULL) 8741 shorten_dir(p); 8742 } 8743 } 8744 8745 #ifdef FEAT_PERL 8746 /* 8747 * "perleval()" function 8748 */ 8749 static void 8750 f_perleval(typval_T *argvars, typval_T *rettv) 8751 { 8752 char_u *str; 8753 char_u buf[NUMBUFLEN]; 8754 8755 str = tv_get_string_buf(&argvars[0], buf); 8756 do_perleval(str, rettv); 8757 } 8758 #endif 8759 8760 #ifdef FEAT_FLOAT 8761 /* 8762 * "pow()" function 8763 */ 8764 static void 8765 f_pow(typval_T *argvars, typval_T *rettv) 8766 { 8767 float_T fx = 0.0, fy = 0.0; 8768 8769 rettv->v_type = VAR_FLOAT; 8770 if (get_float_arg(argvars, &fx) == OK 8771 && get_float_arg(&argvars[1], &fy) == OK) 8772 rettv->vval.v_float = pow(fx, fy); 8773 else 8774 rettv->vval.v_float = 0.0; 8775 } 8776 #endif 8777 8778 /* 8779 * "prevnonblank()" function 8780 */ 8781 static void 8782 f_prevnonblank(typval_T *argvars, typval_T *rettv) 8783 { 8784 linenr_T lnum; 8785 8786 lnum = tv_get_lnum(argvars); 8787 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) 8788 lnum = 0; 8789 else 8790 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL) 8791 --lnum; 8792 rettv->vval.v_number = lnum; 8793 } 8794 8795 /* This dummy va_list is here because: 8796 * - passing a NULL pointer doesn't work when va_list isn't a pointer 8797 * - locally in the function results in a "used before set" warning 8798 * - using va_start() to initialize it gives "function with fixed args" error */ 8799 static va_list ap; 8800 8801 /* 8802 * "printf()" function 8803 */ 8804 static void 8805 f_printf(typval_T *argvars, typval_T *rettv) 8806 { 8807 char_u buf[NUMBUFLEN]; 8808 int len; 8809 char_u *s; 8810 int saved_did_emsg = did_emsg; 8811 char *fmt; 8812 8813 rettv->v_type = VAR_STRING; 8814 rettv->vval.v_string = NULL; 8815 8816 /* Get the required length, allocate the buffer and do it for real. */ 8817 did_emsg = FALSE; 8818 fmt = (char *)tv_get_string_buf(&argvars[0], buf); 8819 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1); 8820 if (!did_emsg) 8821 { 8822 s = alloc(len + 1); 8823 if (s != NULL) 8824 { 8825 rettv->vval.v_string = s; 8826 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt, 8827 ap, argvars + 1); 8828 } 8829 } 8830 did_emsg |= saved_did_emsg; 8831 } 8832 8833 #ifdef FEAT_JOB_CHANNEL 8834 /* 8835 * "prompt_setcallback({buffer}, {callback})" function 8836 */ 8837 static void 8838 f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED) 8839 { 8840 buf_T *buf; 8841 char_u *callback; 8842 partial_T *partial; 8843 8844 if (check_secure()) 8845 return; 8846 buf = tv_get_buf(&argvars[0], FALSE); 8847 if (buf == NULL) 8848 return; 8849 8850 callback = get_callback(&argvars[1], &partial); 8851 if (callback == NULL) 8852 return; 8853 8854 free_callback(buf->b_prompt_callback, buf->b_prompt_partial); 8855 if (partial == NULL) 8856 buf->b_prompt_callback = vim_strsave(callback); 8857 else 8858 /* pointer into the partial */ 8859 buf->b_prompt_callback = callback; 8860 buf->b_prompt_partial = partial; 8861 } 8862 8863 /* 8864 * "prompt_setinterrupt({buffer}, {callback})" function 8865 */ 8866 static void 8867 f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED) 8868 { 8869 buf_T *buf; 8870 char_u *callback; 8871 partial_T *partial; 8872 8873 if (check_secure()) 8874 return; 8875 buf = tv_get_buf(&argvars[0], FALSE); 8876 if (buf == NULL) 8877 return; 8878 8879 callback = get_callback(&argvars[1], &partial); 8880 if (callback == NULL) 8881 return; 8882 8883 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial); 8884 if (partial == NULL) 8885 buf->b_prompt_interrupt = vim_strsave(callback); 8886 else 8887 /* pointer into the partial */ 8888 buf->b_prompt_interrupt = callback; 8889 buf->b_prompt_int_partial = partial; 8890 } 8891 8892 /* 8893 * "prompt_setprompt({buffer}, {text})" function 8894 */ 8895 static void 8896 f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED) 8897 { 8898 buf_T *buf; 8899 char_u *text; 8900 8901 if (check_secure()) 8902 return; 8903 buf = tv_get_buf(&argvars[0], FALSE); 8904 if (buf == NULL) 8905 return; 8906 8907 text = tv_get_string(&argvars[1]); 8908 vim_free(buf->b_prompt_text); 8909 buf->b_prompt_text = vim_strsave(text); 8910 } 8911 #endif 8912 8913 /* 8914 * "pumvisible()" function 8915 */ 8916 static void 8917 f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 8918 { 8919 #ifdef FEAT_INS_EXPAND 8920 if (pum_visible()) 8921 rettv->vval.v_number = 1; 8922 #endif 8923 } 8924 8925 #ifdef FEAT_PYTHON3 8926 /* 8927 * "py3eval()" function 8928 */ 8929 static void 8930 f_py3eval(typval_T *argvars, typval_T *rettv) 8931 { 8932 char_u *str; 8933 char_u buf[NUMBUFLEN]; 8934 8935 if (p_pyx == 0) 8936 p_pyx = 3; 8937 8938 str = tv_get_string_buf(&argvars[0], buf); 8939 do_py3eval(str, rettv); 8940 } 8941 #endif 8942 8943 #ifdef FEAT_PYTHON 8944 /* 8945 * "pyeval()" function 8946 */ 8947 static void 8948 f_pyeval(typval_T *argvars, typval_T *rettv) 8949 { 8950 char_u *str; 8951 char_u buf[NUMBUFLEN]; 8952 8953 if (p_pyx == 0) 8954 p_pyx = 2; 8955 8956 str = tv_get_string_buf(&argvars[0], buf); 8957 do_pyeval(str, rettv); 8958 } 8959 #endif 8960 8961 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) 8962 /* 8963 * "pyxeval()" function 8964 */ 8965 static void 8966 f_pyxeval(typval_T *argvars, typval_T *rettv) 8967 { 8968 # if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3) 8969 init_pyxversion(); 8970 if (p_pyx == 2) 8971 f_pyeval(argvars, rettv); 8972 else 8973 f_py3eval(argvars, rettv); 8974 # elif defined(FEAT_PYTHON) 8975 f_pyeval(argvars, rettv); 8976 # elif defined(FEAT_PYTHON3) 8977 f_py3eval(argvars, rettv); 8978 # endif 8979 } 8980 #endif 8981 8982 /* 8983 * "range()" function 8984 */ 8985 static void 8986 f_range(typval_T *argvars, typval_T *rettv) 8987 { 8988 varnumber_T start; 8989 varnumber_T end; 8990 varnumber_T stride = 1; 8991 varnumber_T i; 8992 int error = FALSE; 8993 8994 start = tv_get_number_chk(&argvars[0], &error); 8995 if (argvars[1].v_type == VAR_UNKNOWN) 8996 { 8997 end = start - 1; 8998 start = 0; 8999 } 9000 else 9001 { 9002 end = tv_get_number_chk(&argvars[1], &error); 9003 if (argvars[2].v_type != VAR_UNKNOWN) 9004 stride = tv_get_number_chk(&argvars[2], &error); 9005 } 9006 9007 if (error) 9008 return; /* type error; errmsg already given */ 9009 if (stride == 0) 9010 emsg(_("E726: Stride is zero")); 9011 else if (stride > 0 ? end + 1 < start : end - 1 > start) 9012 emsg(_("E727: Start past end")); 9013 else 9014 { 9015 if (rettv_list_alloc(rettv) == OK) 9016 for (i = start; stride > 0 ? i <= end : i >= end; i += stride) 9017 if (list_append_number(rettv->vval.v_list, 9018 (varnumber_T)i) == FAIL) 9019 break; 9020 } 9021 } 9022 9023 /* 9024 * "readfile()" function 9025 */ 9026 static void 9027 f_readfile(typval_T *argvars, typval_T *rettv) 9028 { 9029 int binary = FALSE; 9030 int blob = FALSE; 9031 int failed = FALSE; 9032 char_u *fname; 9033 FILE *fd; 9034 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */ 9035 int io_size = sizeof(buf); 9036 int readlen; /* size of last fread() */ 9037 char_u *prev = NULL; /* previously read bytes, if any */ 9038 long prevlen = 0; /* length of data in prev */ 9039 long prevsize = 0; /* size of prev buffer */ 9040 long maxline = MAXLNUM; 9041 long cnt = 0; 9042 char_u *p; /* position in buf */ 9043 char_u *start; /* start of current line */ 9044 9045 if (argvars[1].v_type != VAR_UNKNOWN) 9046 { 9047 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0) 9048 binary = TRUE; 9049 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0) 9050 blob = TRUE; 9051 9052 if (argvars[2].v_type != VAR_UNKNOWN) 9053 maxline = (long)tv_get_number(&argvars[2]); 9054 } 9055 9056 if (blob) 9057 { 9058 if (rettv_blob_alloc(rettv) == FAIL) 9059 return; 9060 } 9061 else 9062 { 9063 if (rettv_list_alloc(rettv) == FAIL) 9064 return; 9065 } 9066 9067 /* Always open the file in binary mode, library functions have a mind of 9068 * their own about CR-LF conversion. */ 9069 fname = tv_get_string(&argvars[0]); 9070 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL) 9071 { 9072 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname); 9073 return; 9074 } 9075 9076 if (blob) 9077 { 9078 if (read_blob(fd, rettv->vval.v_blob) == FAIL) 9079 { 9080 emsg("cannot read file"); 9081 blob_free(rettv->vval.v_blob); 9082 } 9083 fclose(fd); 9084 return; 9085 } 9086 9087 while (cnt < maxline || maxline < 0) 9088 { 9089 readlen = (int)fread(buf, 1, io_size, fd); 9090 9091 /* This for loop processes what was read, but is also entered at end 9092 * of file so that either: 9093 * - an incomplete line gets written 9094 * - a "binary" file gets an empty line at the end if it ends in a 9095 * newline. */ 9096 for (p = buf, start = buf; 9097 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary)); 9098 ++p) 9099 { 9100 if (*p == '\n' || readlen <= 0) 9101 { 9102 listitem_T *li; 9103 char_u *s = NULL; 9104 long_u len = p - start; 9105 9106 /* Finished a line. Remove CRs before NL. */ 9107 if (readlen > 0 && !binary) 9108 { 9109 while (len > 0 && start[len - 1] == '\r') 9110 --len; 9111 /* removal may cross back to the "prev" string */ 9112 if (len == 0) 9113 while (prevlen > 0 && prev[prevlen - 1] == '\r') 9114 --prevlen; 9115 } 9116 if (prevlen == 0) 9117 s = vim_strnsave(start, (int)len); 9118 else 9119 { 9120 /* Change "prev" buffer to be the right size. This way 9121 * the bytes are only copied once, and very long lines are 9122 * allocated only once. */ 9123 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL) 9124 { 9125 mch_memmove(s + prevlen, start, len); 9126 s[prevlen + len] = NUL; 9127 prev = NULL; /* the list will own the string */ 9128 prevlen = prevsize = 0; 9129 } 9130 } 9131 if (s == NULL) 9132 { 9133 do_outofmem_msg((long_u) prevlen + len + 1); 9134 failed = TRUE; 9135 break; 9136 } 9137 9138 if ((li = listitem_alloc()) == NULL) 9139 { 9140 vim_free(s); 9141 failed = TRUE; 9142 break; 9143 } 9144 li->li_tv.v_type = VAR_STRING; 9145 li->li_tv.v_lock = 0; 9146 li->li_tv.vval.v_string = s; 9147 list_append(rettv->vval.v_list, li); 9148 9149 start = p + 1; /* step over newline */ 9150 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0) 9151 break; 9152 } 9153 else if (*p == NUL) 9154 *p = '\n'; 9155 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this 9156 * when finding the BF and check the previous two bytes. */ 9157 else if (*p == 0xbf && enc_utf8 && !binary) 9158 { 9159 /* Find the two bytes before the 0xbf. If p is at buf, or buf 9160 * + 1, these may be in the "prev" string. */ 9161 char_u back1 = p >= buf + 1 ? p[-1] 9162 : prevlen >= 1 ? prev[prevlen - 1] : NUL; 9163 char_u back2 = p >= buf + 2 ? p[-2] 9164 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1] 9165 : prevlen >= 2 ? prev[prevlen - 2] : NUL; 9166 9167 if (back2 == 0xef && back1 == 0xbb) 9168 { 9169 char_u *dest = p - 2; 9170 9171 /* Usually a BOM is at the beginning of a file, and so at 9172 * the beginning of a line; then we can just step over it. 9173 */ 9174 if (start == dest) 9175 start = p + 1; 9176 else 9177 { 9178 /* have to shuffle buf to close gap */ 9179 int adjust_prevlen = 0; 9180 9181 if (dest < buf) 9182 { 9183 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */ 9184 dest = buf; 9185 } 9186 if (readlen > p - buf + 1) 9187 mch_memmove(dest, p + 1, readlen - (p - buf) - 1); 9188 readlen -= 3 - adjust_prevlen; 9189 prevlen -= adjust_prevlen; 9190 p = dest - 1; 9191 } 9192 } 9193 } 9194 } /* for */ 9195 9196 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0) 9197 break; 9198 if (start < p) 9199 { 9200 /* There's part of a line in buf, store it in "prev". */ 9201 if (p - start + prevlen >= prevsize) 9202 { 9203 /* need bigger "prev" buffer */ 9204 char_u *newprev; 9205 9206 /* A common use case is ordinary text files and "prev" gets a 9207 * fragment of a line, so the first allocation is made 9208 * small, to avoid repeatedly 'allocing' large and 9209 * 'reallocing' small. */ 9210 if (prevsize == 0) 9211 prevsize = (long)(p - start); 9212 else 9213 { 9214 long grow50pc = (prevsize * 3) / 2; 9215 long growmin = (long)((p - start) * 2 + prevlen); 9216 prevsize = grow50pc > growmin ? grow50pc : growmin; 9217 } 9218 newprev = prev == NULL ? alloc(prevsize) 9219 : vim_realloc(prev, prevsize); 9220 if (newprev == NULL) 9221 { 9222 do_outofmem_msg((long_u)prevsize); 9223 failed = TRUE; 9224 break; 9225 } 9226 prev = newprev; 9227 } 9228 /* Add the line part to end of "prev". */ 9229 mch_memmove(prev + prevlen, start, p - start); 9230 prevlen += (long)(p - start); 9231 } 9232 } /* while */ 9233 9234 /* 9235 * For a negative line count use only the lines at the end of the file, 9236 * free the rest. 9237 */ 9238 if (!failed && maxline < 0) 9239 while (cnt > -maxline) 9240 { 9241 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first); 9242 --cnt; 9243 } 9244 9245 if (failed) 9246 { 9247 list_free(rettv->vval.v_list); 9248 /* readfile doc says an empty list is returned on error */ 9249 rettv->vval.v_list = list_alloc(); 9250 } 9251 9252 vim_free(prev); 9253 fclose(fd); 9254 } 9255 9256 static void 9257 return_register(int regname, typval_T *rettv) 9258 { 9259 char_u buf[2] = {0, 0}; 9260 9261 buf[0] = (char_u)regname; 9262 rettv->v_type = VAR_STRING; 9263 rettv->vval.v_string = vim_strsave(buf); 9264 } 9265 9266 /* 9267 * "reg_executing()" function 9268 */ 9269 static void 9270 f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv) 9271 { 9272 return_register(reg_executing, rettv); 9273 } 9274 9275 /* 9276 * "reg_recording()" function 9277 */ 9278 static void 9279 f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv) 9280 { 9281 return_register(reg_recording, rettv); 9282 } 9283 9284 #if defined(FEAT_RELTIME) 9285 /* 9286 * Convert a List to proftime_T. 9287 * Return FAIL when there is something wrong. 9288 */ 9289 static int 9290 list2proftime(typval_T *arg, proftime_T *tm) 9291 { 9292 long n1, n2; 9293 int error = FALSE; 9294 9295 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL 9296 || arg->vval.v_list->lv_len != 2) 9297 return FAIL; 9298 n1 = list_find_nr(arg->vval.v_list, 0L, &error); 9299 n2 = list_find_nr(arg->vval.v_list, 1L, &error); 9300 # ifdef WIN3264 9301 tm->HighPart = n1; 9302 tm->LowPart = n2; 9303 # else 9304 tm->tv_sec = n1; 9305 tm->tv_usec = n2; 9306 # endif 9307 return error ? FAIL : OK; 9308 } 9309 #endif /* FEAT_RELTIME */ 9310 9311 /* 9312 * "reltime()" function 9313 */ 9314 static void 9315 f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 9316 { 9317 #ifdef FEAT_RELTIME 9318 proftime_T res; 9319 proftime_T start; 9320 9321 if (argvars[0].v_type == VAR_UNKNOWN) 9322 { 9323 /* No arguments: get current time. */ 9324 profile_start(&res); 9325 } 9326 else if (argvars[1].v_type == VAR_UNKNOWN) 9327 { 9328 if (list2proftime(&argvars[0], &res) == FAIL) 9329 return; 9330 profile_end(&res); 9331 } 9332 else 9333 { 9334 /* Two arguments: compute the difference. */ 9335 if (list2proftime(&argvars[0], &start) == FAIL 9336 || list2proftime(&argvars[1], &res) == FAIL) 9337 return; 9338 profile_sub(&res, &start); 9339 } 9340 9341 if (rettv_list_alloc(rettv) == OK) 9342 { 9343 long n1, n2; 9344 9345 # ifdef WIN3264 9346 n1 = res.HighPart; 9347 n2 = res.LowPart; 9348 # else 9349 n1 = res.tv_sec; 9350 n2 = res.tv_usec; 9351 # endif 9352 list_append_number(rettv->vval.v_list, (varnumber_T)n1); 9353 list_append_number(rettv->vval.v_list, (varnumber_T)n2); 9354 } 9355 #endif 9356 } 9357 9358 #ifdef FEAT_FLOAT 9359 /* 9360 * "reltimefloat()" function 9361 */ 9362 static void 9363 f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv) 9364 { 9365 # ifdef FEAT_RELTIME 9366 proftime_T tm; 9367 # endif 9368 9369 rettv->v_type = VAR_FLOAT; 9370 rettv->vval.v_float = 0; 9371 # ifdef FEAT_RELTIME 9372 if (list2proftime(&argvars[0], &tm) == OK) 9373 rettv->vval.v_float = profile_float(&tm); 9374 # endif 9375 } 9376 #endif 9377 9378 /* 9379 * "reltimestr()" function 9380 */ 9381 static void 9382 f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv) 9383 { 9384 #ifdef FEAT_RELTIME 9385 proftime_T tm; 9386 #endif 9387 9388 rettv->v_type = VAR_STRING; 9389 rettv->vval.v_string = NULL; 9390 #ifdef FEAT_RELTIME 9391 if (list2proftime(&argvars[0], &tm) == OK) 9392 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm)); 9393 #endif 9394 } 9395 9396 #if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) 9397 static void 9398 make_connection(void) 9399 { 9400 if (X_DISPLAY == NULL 9401 # ifdef FEAT_GUI 9402 && !gui.in_use 9403 # endif 9404 ) 9405 { 9406 x_force_connect = TRUE; 9407 setup_term_clip(); 9408 x_force_connect = FALSE; 9409 } 9410 } 9411 9412 static int 9413 check_connection(void) 9414 { 9415 make_connection(); 9416 if (X_DISPLAY == NULL) 9417 { 9418 emsg(_("E240: No connection to the X server")); 9419 return FAIL; 9420 } 9421 return OK; 9422 } 9423 #endif 9424 9425 #ifdef FEAT_CLIENTSERVER 9426 static void 9427 remote_common(typval_T *argvars, typval_T *rettv, int expr) 9428 { 9429 char_u *server_name; 9430 char_u *keys; 9431 char_u *r = NULL; 9432 char_u buf[NUMBUFLEN]; 9433 int timeout = 0; 9434 # ifdef WIN32 9435 HWND w; 9436 # else 9437 Window w; 9438 # endif 9439 9440 if (check_restricted() || check_secure()) 9441 return; 9442 9443 # ifdef FEAT_X11 9444 if (check_connection() == FAIL) 9445 return; 9446 # endif 9447 if (argvars[2].v_type != VAR_UNKNOWN 9448 && argvars[3].v_type != VAR_UNKNOWN) 9449 timeout = tv_get_number(&argvars[3]); 9450 9451 server_name = tv_get_string_chk(&argvars[0]); 9452 if (server_name == NULL) 9453 return; /* type error; errmsg already given */ 9454 keys = tv_get_string_buf(&argvars[1], buf); 9455 # ifdef WIN32 9456 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0) 9457 # else 9458 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout, 9459 0, TRUE) < 0) 9460 # endif 9461 { 9462 if (r != NULL) 9463 { 9464 emsg((char *)r); // sending worked but evaluation failed 9465 vim_free(r); 9466 } 9467 else 9468 semsg(_("E241: Unable to send to %s"), server_name); 9469 return; 9470 } 9471 9472 rettv->vval.v_string = r; 9473 9474 if (argvars[2].v_type != VAR_UNKNOWN) 9475 { 9476 dictitem_T v; 9477 char_u str[30]; 9478 char_u *idvar; 9479 9480 idvar = tv_get_string_chk(&argvars[2]); 9481 if (idvar != NULL && *idvar != NUL) 9482 { 9483 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w); 9484 v.di_tv.v_type = VAR_STRING; 9485 v.di_tv.vval.v_string = vim_strsave(str); 9486 set_var(idvar, &v.di_tv, FALSE); 9487 vim_free(v.di_tv.vval.v_string); 9488 } 9489 } 9490 } 9491 #endif 9492 9493 /* 9494 * "remote_expr()" function 9495 */ 9496 static void 9497 f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv) 9498 { 9499 rettv->v_type = VAR_STRING; 9500 rettv->vval.v_string = NULL; 9501 #ifdef FEAT_CLIENTSERVER 9502 remote_common(argvars, rettv, TRUE); 9503 #endif 9504 } 9505 9506 /* 9507 * "remote_foreground()" function 9508 */ 9509 static void 9510 f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 9511 { 9512 #ifdef FEAT_CLIENTSERVER 9513 # ifdef WIN32 9514 /* On Win32 it's done in this application. */ 9515 { 9516 char_u *server_name = tv_get_string_chk(&argvars[0]); 9517 9518 if (server_name != NULL) 9519 serverForeground(server_name); 9520 } 9521 # else 9522 /* Send a foreground() expression to the server. */ 9523 argvars[1].v_type = VAR_STRING; 9524 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()"); 9525 argvars[2].v_type = VAR_UNKNOWN; 9526 rettv->v_type = VAR_STRING; 9527 rettv->vval.v_string = NULL; 9528 remote_common(argvars, rettv, TRUE); 9529 vim_free(argvars[1].vval.v_string); 9530 # endif 9531 #endif 9532 } 9533 9534 static void 9535 f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv) 9536 { 9537 #ifdef FEAT_CLIENTSERVER 9538 dictitem_T v; 9539 char_u *s = NULL; 9540 # ifdef WIN32 9541 long_u n = 0; 9542 # endif 9543 char_u *serverid; 9544 9545 if (check_restricted() || check_secure()) 9546 { 9547 rettv->vval.v_number = -1; 9548 return; 9549 } 9550 serverid = tv_get_string_chk(&argvars[0]); 9551 if (serverid == NULL) 9552 { 9553 rettv->vval.v_number = -1; 9554 return; /* type error; errmsg already given */ 9555 } 9556 # ifdef WIN32 9557 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n); 9558 if (n == 0) 9559 rettv->vval.v_number = -1; 9560 else 9561 { 9562 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0); 9563 rettv->vval.v_number = (s != NULL); 9564 } 9565 # else 9566 if (check_connection() == FAIL) 9567 return; 9568 9569 rettv->vval.v_number = serverPeekReply(X_DISPLAY, 9570 serverStrToWin(serverid), &s); 9571 # endif 9572 9573 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0) 9574 { 9575 char_u *retvar; 9576 9577 v.di_tv.v_type = VAR_STRING; 9578 v.di_tv.vval.v_string = vim_strsave(s); 9579 retvar = tv_get_string_chk(&argvars[1]); 9580 if (retvar != NULL) 9581 set_var(retvar, &v.di_tv, FALSE); 9582 vim_free(v.di_tv.vval.v_string); 9583 } 9584 #else 9585 rettv->vval.v_number = -1; 9586 #endif 9587 } 9588 9589 static void 9590 f_remote_read(typval_T *argvars UNUSED, typval_T *rettv) 9591 { 9592 char_u *r = NULL; 9593 9594 #ifdef FEAT_CLIENTSERVER 9595 char_u *serverid = tv_get_string_chk(&argvars[0]); 9596 9597 if (serverid != NULL && !check_restricted() && !check_secure()) 9598 { 9599 int timeout = 0; 9600 # ifdef WIN32 9601 /* The server's HWND is encoded in the 'id' parameter */ 9602 long_u n = 0; 9603 # endif 9604 9605 if (argvars[1].v_type != VAR_UNKNOWN) 9606 timeout = tv_get_number(&argvars[1]); 9607 9608 # ifdef WIN32 9609 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n); 9610 if (n != 0) 9611 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout); 9612 if (r == NULL) 9613 # else 9614 if (check_connection() == FAIL 9615 || serverReadReply(X_DISPLAY, serverStrToWin(serverid), 9616 &r, FALSE, timeout) < 0) 9617 # endif 9618 emsg(_("E277: Unable to read a server reply")); 9619 } 9620 #endif 9621 rettv->v_type = VAR_STRING; 9622 rettv->vval.v_string = r; 9623 } 9624 9625 /* 9626 * "remote_send()" function 9627 */ 9628 static void 9629 f_remote_send(typval_T *argvars UNUSED, typval_T *rettv) 9630 { 9631 rettv->v_type = VAR_STRING; 9632 rettv->vval.v_string = NULL; 9633 #ifdef FEAT_CLIENTSERVER 9634 remote_common(argvars, rettv, FALSE); 9635 #endif 9636 } 9637 9638 /* 9639 * "remote_startserver()" function 9640 */ 9641 static void 9642 f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 9643 { 9644 #ifdef FEAT_CLIENTSERVER 9645 char_u *server = tv_get_string_chk(&argvars[0]); 9646 9647 if (server == NULL) 9648 return; /* type error; errmsg already given */ 9649 if (serverName != NULL) 9650 emsg(_("E941: already started a server")); 9651 else 9652 { 9653 # ifdef FEAT_X11 9654 if (check_connection() == OK) 9655 serverRegisterName(X_DISPLAY, server); 9656 # else 9657 serverSetName(server); 9658 # endif 9659 } 9660 #else 9661 emsg(_("E942: +clientserver feature not available")); 9662 #endif 9663 } 9664 9665 /* 9666 * "remove()" function 9667 */ 9668 static void 9669 f_remove(typval_T *argvars, typval_T *rettv) 9670 { 9671 list_T *l; 9672 listitem_T *item, *item2; 9673 listitem_T *li; 9674 long idx; 9675 long end; 9676 char_u *key; 9677 dict_T *d; 9678 dictitem_T *di; 9679 char_u *arg_errmsg = (char_u *)N_("remove() argument"); 9680 int error = FALSE; 9681 9682 if (argvars[0].v_type == VAR_DICT) 9683 { 9684 if (argvars[2].v_type != VAR_UNKNOWN) 9685 semsg(_(e_toomanyarg), "remove()"); 9686 else if ((d = argvars[0].vval.v_dict) != NULL 9687 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE)) 9688 { 9689 key = tv_get_string_chk(&argvars[1]); 9690 if (key != NULL) 9691 { 9692 di = dict_find(d, key, -1); 9693 if (di == NULL) 9694 semsg(_(e_dictkey), key); 9695 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE) 9696 && !var_check_ro(di->di_flags, arg_errmsg, TRUE)) 9697 { 9698 *rettv = di->di_tv; 9699 init_tv(&di->di_tv); 9700 dictitem_remove(d, di); 9701 } 9702 } 9703 } 9704 } 9705 else if (argvars[0].v_type == VAR_BLOB) 9706 { 9707 idx = (long)tv_get_number_chk(&argvars[1], &error); 9708 if (!error) 9709 { 9710 blob_T *b = argvars[0].vval.v_blob; 9711 int len = blob_len(b); 9712 char_u *p; 9713 9714 if (idx < 0) 9715 // count from the end 9716 idx = len + idx; 9717 if (idx < 0 || idx >= len) 9718 { 9719 semsg(_(e_blobidx), idx); 9720 return; 9721 } 9722 if (argvars[2].v_type == VAR_UNKNOWN) 9723 { 9724 // Remove one item, return its value. 9725 p = (char_u *)b->bv_ga.ga_data; 9726 rettv->vval.v_number = (varnumber_T) *(p + idx); 9727 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1); 9728 --b->bv_ga.ga_len; 9729 } 9730 else 9731 { 9732 blob_T *blob; 9733 9734 // Remove range of items, return list with values. 9735 end = (long)tv_get_number_chk(&argvars[2], &error); 9736 if (error) 9737 return; 9738 if (end < 0) 9739 // count from the end 9740 end = len + end; 9741 if (end >= len || idx > end) 9742 { 9743 semsg(_(e_blobidx), end); 9744 return; 9745 } 9746 blob = blob_alloc(); 9747 if (blob == NULL) 9748 return; 9749 blob->bv_ga.ga_len = end - idx + 1; 9750 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL) 9751 { 9752 vim_free(blob); 9753 return; 9754 } 9755 p = (char_u *)b->bv_ga.ga_data; 9756 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx, 9757 (size_t)(end - idx + 1)); 9758 ++blob->bv_refcount; 9759 rettv->v_type = VAR_BLOB; 9760 rettv->vval.v_blob = blob; 9761 9762 mch_memmove(p + idx, p + end + 1, (size_t)(len - end)); 9763 b->bv_ga.ga_len -= end - idx + 1; 9764 } 9765 } 9766 } 9767 else if (argvars[0].v_type != VAR_LIST) 9768 semsg(_(e_listdictblobarg), "remove()"); 9769 else if ((l = argvars[0].vval.v_list) != NULL 9770 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE)) 9771 { 9772 idx = (long)tv_get_number_chk(&argvars[1], &error); 9773 if (error) 9774 ; // type error: do nothing, errmsg already given 9775 else if ((item = list_find(l, idx)) == NULL) 9776 semsg(_(e_listidx), idx); 9777 else 9778 { 9779 if (argvars[2].v_type == VAR_UNKNOWN) 9780 { 9781 /* Remove one item, return its value. */ 9782 vimlist_remove(l, item, item); 9783 *rettv = item->li_tv; 9784 vim_free(item); 9785 } 9786 else 9787 { 9788 // Remove range of items, return list with values. 9789 end = (long)tv_get_number_chk(&argvars[2], &error); 9790 if (error) 9791 ; // type error: do nothing 9792 else if ((item2 = list_find(l, end)) == NULL) 9793 semsg(_(e_listidx), end); 9794 else 9795 { 9796 int cnt = 0; 9797 9798 for (li = item; li != NULL; li = li->li_next) 9799 { 9800 ++cnt; 9801 if (li == item2) 9802 break; 9803 } 9804 if (li == NULL) /* didn't find "item2" after "item" */ 9805 emsg(_(e_invrange)); 9806 else 9807 { 9808 vimlist_remove(l, item, item2); 9809 if (rettv_list_alloc(rettv) == OK) 9810 { 9811 l = rettv->vval.v_list; 9812 l->lv_first = item; 9813 l->lv_last = item2; 9814 item->li_prev = NULL; 9815 item2->li_next = NULL; 9816 l->lv_len = cnt; 9817 } 9818 } 9819 } 9820 } 9821 } 9822 } 9823 } 9824 9825 /* 9826 * "rename({from}, {to})" function 9827 */ 9828 static void 9829 f_rename(typval_T *argvars, typval_T *rettv) 9830 { 9831 char_u buf[NUMBUFLEN]; 9832 9833 if (check_restricted() || check_secure()) 9834 rettv->vval.v_number = -1; 9835 else 9836 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]), 9837 tv_get_string_buf(&argvars[1], buf)); 9838 } 9839 9840 /* 9841 * "repeat()" function 9842 */ 9843 static void 9844 f_repeat(typval_T *argvars, typval_T *rettv) 9845 { 9846 char_u *p; 9847 int n; 9848 int slen; 9849 int len; 9850 char_u *r; 9851 int i; 9852 9853 n = (int)tv_get_number(&argvars[1]); 9854 if (argvars[0].v_type == VAR_LIST) 9855 { 9856 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL) 9857 while (n-- > 0) 9858 if (list_extend(rettv->vval.v_list, 9859 argvars[0].vval.v_list, NULL) == FAIL) 9860 break; 9861 } 9862 else 9863 { 9864 p = tv_get_string(&argvars[0]); 9865 rettv->v_type = VAR_STRING; 9866 rettv->vval.v_string = NULL; 9867 9868 slen = (int)STRLEN(p); 9869 len = slen * n; 9870 if (len <= 0) 9871 return; 9872 9873 r = alloc(len + 1); 9874 if (r != NULL) 9875 { 9876 for (i = 0; i < n; i++) 9877 mch_memmove(r + i * slen, p, (size_t)slen); 9878 r[len] = NUL; 9879 } 9880 9881 rettv->vval.v_string = r; 9882 } 9883 } 9884 9885 /* 9886 * "resolve()" function 9887 */ 9888 static void 9889 f_resolve(typval_T *argvars, typval_T *rettv) 9890 { 9891 char_u *p; 9892 #ifdef HAVE_READLINK 9893 char_u *buf = NULL; 9894 #endif 9895 9896 p = tv_get_string(&argvars[0]); 9897 #ifdef FEAT_SHORTCUT 9898 { 9899 char_u *v = NULL; 9900 9901 v = mch_resolve_shortcut(p); 9902 if (v != NULL) 9903 rettv->vval.v_string = v; 9904 else 9905 rettv->vval.v_string = vim_strsave(p); 9906 } 9907 #else 9908 # ifdef HAVE_READLINK 9909 { 9910 char_u *cpy; 9911 int len; 9912 char_u *remain = NULL; 9913 char_u *q; 9914 int is_relative_to_current = FALSE; 9915 int has_trailing_pathsep = FALSE; 9916 int limit = 100; 9917 9918 p = vim_strsave(p); 9919 9920 if (p[0] == '.' && (vim_ispathsep(p[1]) 9921 || (p[1] == '.' && (vim_ispathsep(p[2]))))) 9922 is_relative_to_current = TRUE; 9923 9924 len = STRLEN(p); 9925 if (len > 0 && after_pathsep(p, p + len)) 9926 { 9927 has_trailing_pathsep = TRUE; 9928 p[len - 1] = NUL; /* the trailing slash breaks readlink() */ 9929 } 9930 9931 q = getnextcomp(p); 9932 if (*q != NUL) 9933 { 9934 /* Separate the first path component in "p", and keep the 9935 * remainder (beginning with the path separator). */ 9936 remain = vim_strsave(q - 1); 9937 q[-1] = NUL; 9938 } 9939 9940 buf = alloc(MAXPATHL + 1); 9941 if (buf == NULL) 9942 goto fail; 9943 9944 for (;;) 9945 { 9946 for (;;) 9947 { 9948 len = readlink((char *)p, (char *)buf, MAXPATHL); 9949 if (len <= 0) 9950 break; 9951 buf[len] = NUL; 9952 9953 if (limit-- == 0) 9954 { 9955 vim_free(p); 9956 vim_free(remain); 9957 emsg(_("E655: Too many symbolic links (cycle?)")); 9958 rettv->vval.v_string = NULL; 9959 goto fail; 9960 } 9961 9962 /* Ensure that the result will have a trailing path separator 9963 * if the argument has one. */ 9964 if (remain == NULL && has_trailing_pathsep) 9965 add_pathsep(buf); 9966 9967 /* Separate the first path component in the link value and 9968 * concatenate the remainders. */ 9969 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf); 9970 if (*q != NUL) 9971 { 9972 if (remain == NULL) 9973 remain = vim_strsave(q - 1); 9974 else 9975 { 9976 cpy = concat_str(q - 1, remain); 9977 if (cpy != NULL) 9978 { 9979 vim_free(remain); 9980 remain = cpy; 9981 } 9982 } 9983 q[-1] = NUL; 9984 } 9985 9986 q = gettail(p); 9987 if (q > p && *q == NUL) 9988 { 9989 /* Ignore trailing path separator. */ 9990 q[-1] = NUL; 9991 q = gettail(p); 9992 } 9993 if (q > p && !mch_isFullName(buf)) 9994 { 9995 /* symlink is relative to directory of argument */ 9996 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1)); 9997 if (cpy != NULL) 9998 { 9999 STRCPY(cpy, p); 10000 STRCPY(gettail(cpy), buf); 10001 vim_free(p); 10002 p = cpy; 10003 } 10004 } 10005 else 10006 { 10007 vim_free(p); 10008 p = vim_strsave(buf); 10009 } 10010 } 10011 10012 if (remain == NULL) 10013 break; 10014 10015 /* Append the first path component of "remain" to "p". */ 10016 q = getnextcomp(remain + 1); 10017 len = q - remain - (*q != NUL); 10018 cpy = vim_strnsave(p, STRLEN(p) + len); 10019 if (cpy != NULL) 10020 { 10021 STRNCAT(cpy, remain, len); 10022 vim_free(p); 10023 p = cpy; 10024 } 10025 /* Shorten "remain". */ 10026 if (*q != NUL) 10027 STRMOVE(remain, q - 1); 10028 else 10029 VIM_CLEAR(remain); 10030 } 10031 10032 /* If the result is a relative path name, make it explicitly relative to 10033 * the current directory if and only if the argument had this form. */ 10034 if (!vim_ispathsep(*p)) 10035 { 10036 if (is_relative_to_current 10037 && *p != NUL 10038 && !(p[0] == '.' 10039 && (p[1] == NUL 10040 || vim_ispathsep(p[1]) 10041 || (p[1] == '.' 10042 && (p[2] == NUL 10043 || vim_ispathsep(p[2])))))) 10044 { 10045 /* Prepend "./". */ 10046 cpy = concat_str((char_u *)"./", p); 10047 if (cpy != NULL) 10048 { 10049 vim_free(p); 10050 p = cpy; 10051 } 10052 } 10053 else if (!is_relative_to_current) 10054 { 10055 /* Strip leading "./". */ 10056 q = p; 10057 while (q[0] == '.' && vim_ispathsep(q[1])) 10058 q += 2; 10059 if (q > p) 10060 STRMOVE(p, p + 2); 10061 } 10062 } 10063 10064 /* Ensure that the result will have no trailing path separator 10065 * if the argument had none. But keep "/" or "//". */ 10066 if (!has_trailing_pathsep) 10067 { 10068 q = p + STRLEN(p); 10069 if (after_pathsep(p, q)) 10070 *gettail_sep(p) = NUL; 10071 } 10072 10073 rettv->vval.v_string = p; 10074 } 10075 # else 10076 rettv->vval.v_string = vim_strsave(p); 10077 # endif 10078 #endif 10079 10080 simplify_filename(rettv->vval.v_string); 10081 10082 #ifdef HAVE_READLINK 10083 fail: 10084 vim_free(buf); 10085 #endif 10086 rettv->v_type = VAR_STRING; 10087 } 10088 10089 /* 10090 * "reverse({list})" function 10091 */ 10092 static void 10093 f_reverse(typval_T *argvars, typval_T *rettv) 10094 { 10095 list_T *l; 10096 listitem_T *li, *ni; 10097 10098 if (argvars[0].v_type == VAR_BLOB) 10099 { 10100 blob_T *b = argvars[0].vval.v_blob; 10101 int i, len = blob_len(b); 10102 10103 for (i = 0; i < len / 2; i++) 10104 { 10105 int tmp = blob_get(b, i); 10106 10107 blob_set(b, i, blob_get(b, len - i - 1)); 10108 blob_set(b, len - i - 1, tmp); 10109 } 10110 rettv_blob_set(rettv, b); 10111 return; 10112 } 10113 10114 if (argvars[0].v_type != VAR_LIST) 10115 semsg(_(e_listblobarg), "reverse()"); 10116 else if ((l = argvars[0].vval.v_list) != NULL 10117 && !tv_check_lock(l->lv_lock, 10118 (char_u *)N_("reverse() argument"), TRUE)) 10119 { 10120 li = l->lv_last; 10121 l->lv_first = l->lv_last = NULL; 10122 l->lv_len = 0; 10123 while (li != NULL) 10124 { 10125 ni = li->li_prev; 10126 list_append(l, li); 10127 li = ni; 10128 } 10129 rettv_list_set(rettv, l); 10130 l->lv_idx = l->lv_len - l->lv_idx - 1; 10131 } 10132 } 10133 10134 #define SP_NOMOVE 0x01 /* don't move cursor */ 10135 #define SP_REPEAT 0x02 /* repeat to find outer pair */ 10136 #define SP_RETCOUNT 0x04 /* return matchcount */ 10137 #define SP_SETPCMARK 0x08 /* set previous context mark */ 10138 #define SP_START 0x10 /* accept match at start position */ 10139 #define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */ 10140 #define SP_END 0x40 /* leave cursor at end of match */ 10141 #define SP_COLUMN 0x80 /* start at cursor column */ 10142 10143 /* 10144 * Get flags for a search function. 10145 * Possibly sets "p_ws". 10146 * Returns BACKWARD, FORWARD or zero (for an error). 10147 */ 10148 static int 10149 get_search_arg(typval_T *varp, int *flagsp) 10150 { 10151 int dir = FORWARD; 10152 char_u *flags; 10153 char_u nbuf[NUMBUFLEN]; 10154 int mask; 10155 10156 if (varp->v_type != VAR_UNKNOWN) 10157 { 10158 flags = tv_get_string_buf_chk(varp, nbuf); 10159 if (flags == NULL) 10160 return 0; /* type error; errmsg already given */ 10161 while (*flags != NUL) 10162 { 10163 switch (*flags) 10164 { 10165 case 'b': dir = BACKWARD; break; 10166 case 'w': p_ws = TRUE; break; 10167 case 'W': p_ws = FALSE; break; 10168 default: mask = 0; 10169 if (flagsp != NULL) 10170 switch (*flags) 10171 { 10172 case 'c': mask = SP_START; break; 10173 case 'e': mask = SP_END; break; 10174 case 'm': mask = SP_RETCOUNT; break; 10175 case 'n': mask = SP_NOMOVE; break; 10176 case 'p': mask = SP_SUBPAT; break; 10177 case 'r': mask = SP_REPEAT; break; 10178 case 's': mask = SP_SETPCMARK; break; 10179 case 'z': mask = SP_COLUMN; break; 10180 } 10181 if (mask == 0) 10182 { 10183 semsg(_(e_invarg2), flags); 10184 dir = 0; 10185 } 10186 else 10187 *flagsp |= mask; 10188 } 10189 if (dir == 0) 10190 break; 10191 ++flags; 10192 } 10193 } 10194 return dir; 10195 } 10196 10197 /* 10198 * Shared by search() and searchpos() functions. 10199 */ 10200 static int 10201 search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) 10202 { 10203 int flags; 10204 char_u *pat; 10205 pos_T pos; 10206 pos_T save_cursor; 10207 int save_p_ws = p_ws; 10208 int dir; 10209 int retval = 0; /* default: FAIL */ 10210 long lnum_stop = 0; 10211 proftime_T tm; 10212 #ifdef FEAT_RELTIME 10213 long time_limit = 0; 10214 #endif 10215 int options = SEARCH_KEEP; 10216 int subpatnum; 10217 10218 pat = tv_get_string(&argvars[0]); 10219 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */ 10220 if (dir == 0) 10221 goto theend; 10222 flags = *flagsp; 10223 if (flags & SP_START) 10224 options |= SEARCH_START; 10225 if (flags & SP_END) 10226 options |= SEARCH_END; 10227 if (flags & SP_COLUMN) 10228 options |= SEARCH_COL; 10229 10230 /* Optional arguments: line number to stop searching and timeout. */ 10231 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) 10232 { 10233 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL); 10234 if (lnum_stop < 0) 10235 goto theend; 10236 #ifdef FEAT_RELTIME 10237 if (argvars[3].v_type != VAR_UNKNOWN) 10238 { 10239 time_limit = (long)tv_get_number_chk(&argvars[3], NULL); 10240 if (time_limit < 0) 10241 goto theend; 10242 } 10243 #endif 10244 } 10245 10246 #ifdef FEAT_RELTIME 10247 /* Set the time limit, if there is one. */ 10248 profile_setlimit(time_limit, &tm); 10249 #endif 10250 10251 /* 10252 * This function does not accept SP_REPEAT and SP_RETCOUNT flags. 10253 * Check to make sure only those flags are set. 10254 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both 10255 * flags cannot be set. Check for that condition also. 10256 */ 10257 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0) 10258 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) 10259 { 10260 semsg(_(e_invarg2), tv_get_string(&argvars[1])); 10261 goto theend; 10262 } 10263 10264 pos = save_cursor = curwin->w_cursor; 10265 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L, 10266 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL); 10267 if (subpatnum != FAIL) 10268 { 10269 if (flags & SP_SUBPAT) 10270 retval = subpatnum; 10271 else 10272 retval = pos.lnum; 10273 if (flags & SP_SETPCMARK) 10274 setpcmark(); 10275 curwin->w_cursor = pos; 10276 if (match_pos != NULL) 10277 { 10278 /* Store the match cursor position */ 10279 match_pos->lnum = pos.lnum; 10280 match_pos->col = pos.col + 1; 10281 } 10282 /* "/$" will put the cursor after the end of the line, may need to 10283 * correct that here */ 10284 check_cursor(); 10285 } 10286 10287 /* If 'n' flag is used: restore cursor position. */ 10288 if (flags & SP_NOMOVE) 10289 curwin->w_cursor = save_cursor; 10290 else 10291 curwin->w_set_curswant = TRUE; 10292 theend: 10293 p_ws = save_p_ws; 10294 10295 return retval; 10296 } 10297 10298 #ifdef FEAT_FLOAT 10299 10300 /* 10301 * round() is not in C90, use ceil() or floor() instead. 10302 */ 10303 float_T 10304 vim_round(float_T f) 10305 { 10306 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5); 10307 } 10308 10309 /* 10310 * "round({float})" function 10311 */ 10312 static void 10313 f_round(typval_T *argvars, typval_T *rettv) 10314 { 10315 float_T f = 0.0; 10316 10317 rettv->v_type = VAR_FLOAT; 10318 if (get_float_arg(argvars, &f) == OK) 10319 rettv->vval.v_float = vim_round(f); 10320 else 10321 rettv->vval.v_float = 0.0; 10322 } 10323 #endif 10324 10325 /* 10326 * "screenattr()" function 10327 */ 10328 static void 10329 f_screenattr(typval_T *argvars, typval_T *rettv) 10330 { 10331 int row; 10332 int col; 10333 int c; 10334 10335 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1; 10336 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1; 10337 if (row < 0 || row >= screen_Rows 10338 || col < 0 || col >= screen_Columns) 10339 c = -1; 10340 else 10341 c = ScreenAttrs[LineOffset[row] + col]; 10342 rettv->vval.v_number = c; 10343 } 10344 10345 /* 10346 * "screenchar()" function 10347 */ 10348 static void 10349 f_screenchar(typval_T *argvars, typval_T *rettv) 10350 { 10351 int row; 10352 int col; 10353 int off; 10354 int c; 10355 10356 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1; 10357 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1; 10358 if (row < 0 || row >= screen_Rows 10359 || col < 0 || col >= screen_Columns) 10360 c = -1; 10361 else 10362 { 10363 off = LineOffset[row] + col; 10364 if (enc_utf8 && ScreenLinesUC[off] != 0) 10365 c = ScreenLinesUC[off]; 10366 else 10367 c = ScreenLines[off]; 10368 } 10369 rettv->vval.v_number = c; 10370 } 10371 10372 /* 10373 * "screencol()" function 10374 * 10375 * First column is 1 to be consistent with virtcol(). 10376 */ 10377 static void 10378 f_screencol(typval_T *argvars UNUSED, typval_T *rettv) 10379 { 10380 rettv->vval.v_number = screen_screencol() + 1; 10381 } 10382 10383 /* 10384 * "screenrow()" function 10385 */ 10386 static void 10387 f_screenrow(typval_T *argvars UNUSED, typval_T *rettv) 10388 { 10389 rettv->vval.v_number = screen_screenrow() + 1; 10390 } 10391 10392 /* 10393 * "search()" function 10394 */ 10395 static void 10396 f_search(typval_T *argvars, typval_T *rettv) 10397 { 10398 int flags = 0; 10399 10400 rettv->vval.v_number = search_cmn(argvars, NULL, &flags); 10401 } 10402 10403 /* 10404 * "searchdecl()" function 10405 */ 10406 static void 10407 f_searchdecl(typval_T *argvars, typval_T *rettv) 10408 { 10409 int locally = 1; 10410 int thisblock = 0; 10411 int error = FALSE; 10412 char_u *name; 10413 10414 rettv->vval.v_number = 1; /* default: FAIL */ 10415 10416 name = tv_get_string_chk(&argvars[0]); 10417 if (argvars[1].v_type != VAR_UNKNOWN) 10418 { 10419 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0; 10420 if (!error && argvars[2].v_type != VAR_UNKNOWN) 10421 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0; 10422 } 10423 if (!error && name != NULL) 10424 rettv->vval.v_number = find_decl(name, (int)STRLEN(name), 10425 locally, thisblock, SEARCH_KEEP) == FAIL; 10426 } 10427 10428 /* 10429 * Used by searchpair() and searchpairpos() 10430 */ 10431 static int 10432 searchpair_cmn(typval_T *argvars, pos_T *match_pos) 10433 { 10434 char_u *spat, *mpat, *epat; 10435 typval_T *skip; 10436 int save_p_ws = p_ws; 10437 int dir; 10438 int flags = 0; 10439 char_u nbuf1[NUMBUFLEN]; 10440 char_u nbuf2[NUMBUFLEN]; 10441 int retval = 0; /* default: FAIL */ 10442 long lnum_stop = 0; 10443 long time_limit = 0; 10444 10445 /* Get the three pattern arguments: start, middle, end. Will result in an 10446 * error if not a valid argument. */ 10447 spat = tv_get_string_chk(&argvars[0]); 10448 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1); 10449 epat = tv_get_string_buf_chk(&argvars[2], nbuf2); 10450 if (spat == NULL || mpat == NULL || epat == NULL) 10451 goto theend; /* type error */ 10452 10453 /* Handle the optional fourth argument: flags */ 10454 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */ 10455 if (dir == 0) 10456 goto theend; 10457 10458 /* Don't accept SP_END or SP_SUBPAT. 10459 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set. 10460 */ 10461 if ((flags & (SP_END | SP_SUBPAT)) != 0 10462 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) 10463 { 10464 semsg(_(e_invarg2), tv_get_string(&argvars[3])); 10465 goto theend; 10466 } 10467 10468 /* Using 'r' implies 'W', otherwise it doesn't work. */ 10469 if (flags & SP_REPEAT) 10470 p_ws = FALSE; 10471 10472 /* Optional fifth argument: skip expression */ 10473 if (argvars[3].v_type == VAR_UNKNOWN 10474 || argvars[4].v_type == VAR_UNKNOWN) 10475 skip = NULL; 10476 else 10477 { 10478 skip = &argvars[4]; 10479 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL 10480 && skip->v_type != VAR_STRING) 10481 { 10482 /* Type error */ 10483 semsg(_(e_invarg2), tv_get_string(&argvars[4])); 10484 goto theend; 10485 } 10486 if (argvars[5].v_type != VAR_UNKNOWN) 10487 { 10488 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL); 10489 if (lnum_stop < 0) 10490 { 10491 semsg(_(e_invarg2), tv_get_string(&argvars[5])); 10492 goto theend; 10493 } 10494 #ifdef FEAT_RELTIME 10495 if (argvars[6].v_type != VAR_UNKNOWN) 10496 { 10497 time_limit = (long)tv_get_number_chk(&argvars[6], NULL); 10498 if (time_limit < 0) 10499 { 10500 semsg(_(e_invarg2), tv_get_string(&argvars[6])); 10501 goto theend; 10502 } 10503 } 10504 #endif 10505 } 10506 } 10507 10508 retval = do_searchpair(spat, mpat, epat, dir, skip, flags, 10509 match_pos, lnum_stop, time_limit); 10510 10511 theend: 10512 p_ws = save_p_ws; 10513 10514 return retval; 10515 } 10516 10517 /* 10518 * "searchpair()" function 10519 */ 10520 static void 10521 f_searchpair(typval_T *argvars, typval_T *rettv) 10522 { 10523 rettv->vval.v_number = searchpair_cmn(argvars, NULL); 10524 } 10525 10526 /* 10527 * "searchpairpos()" function 10528 */ 10529 static void 10530 f_searchpairpos(typval_T *argvars, typval_T *rettv) 10531 { 10532 pos_T match_pos; 10533 int lnum = 0; 10534 int col = 0; 10535 10536 if (rettv_list_alloc(rettv) == FAIL) 10537 return; 10538 10539 if (searchpair_cmn(argvars, &match_pos) > 0) 10540 { 10541 lnum = match_pos.lnum; 10542 col = match_pos.col; 10543 } 10544 10545 list_append_number(rettv->vval.v_list, (varnumber_T)lnum); 10546 list_append_number(rettv->vval.v_list, (varnumber_T)col); 10547 } 10548 10549 /* 10550 * Search for a start/middle/end thing. 10551 * Used by searchpair(), see its documentation for the details. 10552 * Returns 0 or -1 for no match, 10553 */ 10554 long 10555 do_searchpair( 10556 char_u *spat, /* start pattern */ 10557 char_u *mpat, /* middle pattern */ 10558 char_u *epat, /* end pattern */ 10559 int dir, /* BACKWARD or FORWARD */ 10560 typval_T *skip, /* skip expression */ 10561 int flags, /* SP_SETPCMARK and other SP_ values */ 10562 pos_T *match_pos, 10563 linenr_T lnum_stop, /* stop at this line if not zero */ 10564 long time_limit UNUSED) /* stop after this many msec */ 10565 { 10566 char_u *save_cpo; 10567 char_u *pat, *pat2 = NULL, *pat3 = NULL; 10568 long retval = 0; 10569 pos_T pos; 10570 pos_T firstpos; 10571 pos_T foundpos; 10572 pos_T save_cursor; 10573 pos_T save_pos; 10574 int n; 10575 int r; 10576 int nest = 1; 10577 int use_skip = FALSE; 10578 int err; 10579 int options = SEARCH_KEEP; 10580 proftime_T tm; 10581 10582 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ 10583 save_cpo = p_cpo; 10584 p_cpo = empty_option; 10585 10586 #ifdef FEAT_RELTIME 10587 /* Set the time limit, if there is one. */ 10588 profile_setlimit(time_limit, &tm); 10589 #endif 10590 10591 /* Make two search patterns: start/end (pat2, for in nested pairs) and 10592 * start/middle/end (pat3, for the top pair). */ 10593 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17)); 10594 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25)); 10595 if (pat2 == NULL || pat3 == NULL) 10596 goto theend; 10597 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat); 10598 if (*mpat == NUL) 10599 STRCPY(pat3, pat2); 10600 else 10601 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", 10602 spat, epat, mpat); 10603 if (flags & SP_START) 10604 options |= SEARCH_START; 10605 10606 if (skip != NULL) 10607 { 10608 /* Empty string means to not use the skip expression. */ 10609 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC) 10610 use_skip = skip->vval.v_string != NULL 10611 && *skip->vval.v_string != NUL; 10612 } 10613 10614 save_cursor = curwin->w_cursor; 10615 pos = curwin->w_cursor; 10616 CLEAR_POS(&firstpos); 10617 CLEAR_POS(&foundpos); 10618 pat = pat3; 10619 for (;;) 10620 { 10621 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L, 10622 options, RE_SEARCH, lnum_stop, &tm, NULL); 10623 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))) 10624 /* didn't find it or found the first match again: FAIL */ 10625 break; 10626 10627 if (firstpos.lnum == 0) 10628 firstpos = pos; 10629 if (EQUAL_POS(pos, foundpos)) 10630 { 10631 /* Found the same position again. Can happen with a pattern that 10632 * has "\zs" at the end and searching backwards. Advance one 10633 * character and try again. */ 10634 if (dir == BACKWARD) 10635 decl(&pos); 10636 else 10637 incl(&pos); 10638 } 10639 foundpos = pos; 10640 10641 /* clear the start flag to avoid getting stuck here */ 10642 options &= ~SEARCH_START; 10643 10644 /* If the skip pattern matches, ignore this match. */ 10645 if (use_skip) 10646 { 10647 save_pos = curwin->w_cursor; 10648 curwin->w_cursor = pos; 10649 err = FALSE; 10650 r = eval_expr_to_bool(skip, &err); 10651 curwin->w_cursor = save_pos; 10652 if (err) 10653 { 10654 /* Evaluating {skip} caused an error, break here. */ 10655 curwin->w_cursor = save_cursor; 10656 retval = -1; 10657 break; 10658 } 10659 if (r) 10660 continue; 10661 } 10662 10663 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2)) 10664 { 10665 /* Found end when searching backwards or start when searching 10666 * forward: nested pair. */ 10667 ++nest; 10668 pat = pat2; /* nested, don't search for middle */ 10669 } 10670 else 10671 { 10672 /* Found end when searching forward or start when searching 10673 * backward: end of (nested) pair; or found middle in outer pair. */ 10674 if (--nest == 1) 10675 pat = pat3; /* outer level, search for middle */ 10676 } 10677 10678 if (nest == 0) 10679 { 10680 /* Found the match: return matchcount or line number. */ 10681 if (flags & SP_RETCOUNT) 10682 ++retval; 10683 else 10684 retval = pos.lnum; 10685 if (flags & SP_SETPCMARK) 10686 setpcmark(); 10687 curwin->w_cursor = pos; 10688 if (!(flags & SP_REPEAT)) 10689 break; 10690 nest = 1; /* search for next unmatched */ 10691 } 10692 } 10693 10694 if (match_pos != NULL) 10695 { 10696 /* Store the match cursor position */ 10697 match_pos->lnum = curwin->w_cursor.lnum; 10698 match_pos->col = curwin->w_cursor.col + 1; 10699 } 10700 10701 /* If 'n' flag is used or search failed: restore cursor position. */ 10702 if ((flags & SP_NOMOVE) || retval == 0) 10703 curwin->w_cursor = save_cursor; 10704 10705 theend: 10706 vim_free(pat2); 10707 vim_free(pat3); 10708 if (p_cpo == empty_option) 10709 p_cpo = save_cpo; 10710 else 10711 /* Darn, evaluating the {skip} expression changed the value. */ 10712 free_string_option(save_cpo); 10713 10714 return retval; 10715 } 10716 10717 /* 10718 * "searchpos()" function 10719 */ 10720 static void 10721 f_searchpos(typval_T *argvars, typval_T *rettv) 10722 { 10723 pos_T match_pos; 10724 int lnum = 0; 10725 int col = 0; 10726 int n; 10727 int flags = 0; 10728 10729 if (rettv_list_alloc(rettv) == FAIL) 10730 return; 10731 10732 n = search_cmn(argvars, &match_pos, &flags); 10733 if (n > 0) 10734 { 10735 lnum = match_pos.lnum; 10736 col = match_pos.col; 10737 } 10738 10739 list_append_number(rettv->vval.v_list, (varnumber_T)lnum); 10740 list_append_number(rettv->vval.v_list, (varnumber_T)col); 10741 if (flags & SP_SUBPAT) 10742 list_append_number(rettv->vval.v_list, (varnumber_T)n); 10743 } 10744 10745 static void 10746 f_server2client(typval_T *argvars UNUSED, typval_T *rettv) 10747 { 10748 #ifdef FEAT_CLIENTSERVER 10749 char_u buf[NUMBUFLEN]; 10750 char_u *server = tv_get_string_chk(&argvars[0]); 10751 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf); 10752 10753 rettv->vval.v_number = -1; 10754 if (server == NULL || reply == NULL) 10755 return; 10756 if (check_restricted() || check_secure()) 10757 return; 10758 # ifdef FEAT_X11 10759 if (check_connection() == FAIL) 10760 return; 10761 # endif 10762 10763 if (serverSendReply(server, reply) < 0) 10764 { 10765 emsg(_("E258: Unable to send to client")); 10766 return; 10767 } 10768 rettv->vval.v_number = 0; 10769 #else 10770 rettv->vval.v_number = -1; 10771 #endif 10772 } 10773 10774 static void 10775 f_serverlist(typval_T *argvars UNUSED, typval_T *rettv) 10776 { 10777 char_u *r = NULL; 10778 10779 #ifdef FEAT_CLIENTSERVER 10780 # ifdef WIN32 10781 r = serverGetVimNames(); 10782 # else 10783 make_connection(); 10784 if (X_DISPLAY != NULL) 10785 r = serverGetVimNames(X_DISPLAY); 10786 # endif 10787 #endif 10788 rettv->v_type = VAR_STRING; 10789 rettv->vval.v_string = r; 10790 } 10791 10792 /* 10793 * "setbufline()" function 10794 */ 10795 static void 10796 f_setbufline(typval_T *argvars, typval_T *rettv) 10797 { 10798 linenr_T lnum; 10799 buf_T *buf; 10800 10801 buf = tv_get_buf(&argvars[0], FALSE); 10802 if (buf == NULL) 10803 rettv->vval.v_number = 1; /* FAIL */ 10804 else 10805 { 10806 lnum = tv_get_lnum_buf(&argvars[1], buf); 10807 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv); 10808 } 10809 } 10810 10811 /* 10812 * "setbufvar()" function 10813 */ 10814 static void 10815 f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED) 10816 { 10817 buf_T *buf; 10818 char_u *varname, *bufvarname; 10819 typval_T *varp; 10820 char_u nbuf[NUMBUFLEN]; 10821 10822 if (check_restricted() || check_secure()) 10823 return; 10824 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */ 10825 varname = tv_get_string_chk(&argvars[1]); 10826 buf = tv_get_buf(&argvars[0], FALSE); 10827 varp = &argvars[2]; 10828 10829 if (buf != NULL && varname != NULL && varp != NULL) 10830 { 10831 if (*varname == '&') 10832 { 10833 long numval; 10834 char_u *strval; 10835 int error = FALSE; 10836 aco_save_T aco; 10837 10838 /* set curbuf to be our buf, temporarily */ 10839 aucmd_prepbuf(&aco, buf); 10840 10841 ++varname; 10842 numval = (long)tv_get_number_chk(varp, &error); 10843 strval = tv_get_string_buf_chk(varp, nbuf); 10844 if (!error && strval != NULL) 10845 set_option_value(varname, numval, strval, OPT_LOCAL); 10846 10847 /* reset notion of buffer */ 10848 aucmd_restbuf(&aco); 10849 } 10850 else 10851 { 10852 buf_T *save_curbuf = curbuf; 10853 10854 bufvarname = alloc((unsigned)STRLEN(varname) + 3); 10855 if (bufvarname != NULL) 10856 { 10857 curbuf = buf; 10858 STRCPY(bufvarname, "b:"); 10859 STRCPY(bufvarname + 2, varname); 10860 set_var(bufvarname, varp, TRUE); 10861 vim_free(bufvarname); 10862 curbuf = save_curbuf; 10863 } 10864 } 10865 } 10866 } 10867 10868 static void 10869 f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED) 10870 { 10871 dict_T *d; 10872 dictitem_T *di; 10873 char_u *csearch; 10874 10875 if (argvars[0].v_type != VAR_DICT) 10876 { 10877 emsg(_(e_dictreq)); 10878 return; 10879 } 10880 10881 if ((d = argvars[0].vval.v_dict) != NULL) 10882 { 10883 csearch = dict_get_string(d, (char_u *)"char", FALSE); 10884 if (csearch != NULL) 10885 { 10886 if (enc_utf8) 10887 { 10888 int pcc[MAX_MCO]; 10889 int c = utfc_ptr2char(csearch, pcc); 10890 10891 set_last_csearch(c, csearch, utfc_ptr2len(csearch)); 10892 } 10893 else 10894 set_last_csearch(PTR2CHAR(csearch), 10895 csearch, MB_PTR2LEN(csearch)); 10896 } 10897 10898 di = dict_find(d, (char_u *)"forward", -1); 10899 if (di != NULL) 10900 set_csearch_direction((int)tv_get_number(&di->di_tv) 10901 ? FORWARD : BACKWARD); 10902 10903 di = dict_find(d, (char_u *)"until", -1); 10904 if (di != NULL) 10905 set_csearch_until(!!tv_get_number(&di->di_tv)); 10906 } 10907 } 10908 10909 /* 10910 * "setcmdpos()" function 10911 */ 10912 static void 10913 f_setcmdpos(typval_T *argvars, typval_T *rettv) 10914 { 10915 int pos = (int)tv_get_number(&argvars[0]) - 1; 10916 10917 if (pos >= 0) 10918 rettv->vval.v_number = set_cmdline_pos(pos); 10919 } 10920 10921 /* 10922 * "setfperm({fname}, {mode})" function 10923 */ 10924 static void 10925 f_setfperm(typval_T *argvars, typval_T *rettv) 10926 { 10927 char_u *fname; 10928 char_u modebuf[NUMBUFLEN]; 10929 char_u *mode_str; 10930 int i; 10931 int mask; 10932 int mode = 0; 10933 10934 rettv->vval.v_number = 0; 10935 fname = tv_get_string_chk(&argvars[0]); 10936 if (fname == NULL) 10937 return; 10938 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf); 10939 if (mode_str == NULL) 10940 return; 10941 if (STRLEN(mode_str) != 9) 10942 { 10943 semsg(_(e_invarg2), mode_str); 10944 return; 10945 } 10946 10947 mask = 1; 10948 for (i = 8; i >= 0; --i) 10949 { 10950 if (mode_str[i] != '-') 10951 mode |= mask; 10952 mask = mask << 1; 10953 } 10954 rettv->vval.v_number = mch_setperm(fname, mode) == OK; 10955 } 10956 10957 /* 10958 * "setline()" function 10959 */ 10960 static void 10961 f_setline(typval_T *argvars, typval_T *rettv) 10962 { 10963 linenr_T lnum = tv_get_lnum(&argvars[0]); 10964 10965 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv); 10966 } 10967 10968 /* 10969 * Used by "setqflist()" and "setloclist()" functions 10970 */ 10971 static void 10972 set_qf_ll_list( 10973 win_T *wp UNUSED, 10974 typval_T *list_arg UNUSED, 10975 typval_T *action_arg UNUSED, 10976 typval_T *what_arg UNUSED, 10977 typval_T *rettv) 10978 { 10979 #ifdef FEAT_QUICKFIX 10980 static char *e_invact = N_("E927: Invalid action: '%s'"); 10981 char_u *act; 10982 int action = 0; 10983 static int recursive = 0; 10984 #endif 10985 10986 rettv->vval.v_number = -1; 10987 10988 #ifdef FEAT_QUICKFIX 10989 if (list_arg->v_type != VAR_LIST) 10990 emsg(_(e_listreq)); 10991 else if (recursive != 0) 10992 emsg(_(e_au_recursive)); 10993 else 10994 { 10995 list_T *l = list_arg->vval.v_list; 10996 dict_T *d = NULL; 10997 int valid_dict = TRUE; 10998 10999 if (action_arg->v_type == VAR_STRING) 11000 { 11001 act = tv_get_string_chk(action_arg); 11002 if (act == NULL) 11003 return; /* type error; errmsg already given */ 11004 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') && 11005 act[1] == NUL) 11006 action = *act; 11007 else 11008 semsg(_(e_invact), act); 11009 } 11010 else if (action_arg->v_type == VAR_UNKNOWN) 11011 action = ' '; 11012 else 11013 emsg(_(e_stringreq)); 11014 11015 if (action_arg->v_type != VAR_UNKNOWN 11016 && what_arg->v_type != VAR_UNKNOWN) 11017 { 11018 if (what_arg->v_type == VAR_DICT) 11019 d = what_arg->vval.v_dict; 11020 else 11021 { 11022 emsg(_(e_dictreq)); 11023 valid_dict = FALSE; 11024 } 11025 } 11026 11027 ++recursive; 11028 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action, 11029 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"), 11030 d) == OK) 11031 rettv->vval.v_number = 0; 11032 --recursive; 11033 } 11034 #endif 11035 } 11036 11037 /* 11038 * "setloclist()" function 11039 */ 11040 static void 11041 f_setloclist(typval_T *argvars, typval_T *rettv) 11042 { 11043 win_T *win; 11044 11045 rettv->vval.v_number = -1; 11046 11047 win = find_win_by_nr_or_id(&argvars[0]); 11048 if (win != NULL) 11049 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv); 11050 } 11051 11052 /* 11053 * "setmatches()" function 11054 */ 11055 static void 11056 f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 11057 { 11058 #ifdef FEAT_SEARCH_EXTRA 11059 list_T *l; 11060 listitem_T *li; 11061 dict_T *d; 11062 list_T *s = NULL; 11063 11064 rettv->vval.v_number = -1; 11065 if (argvars[0].v_type != VAR_LIST) 11066 { 11067 emsg(_(e_listreq)); 11068 return; 11069 } 11070 if ((l = argvars[0].vval.v_list) != NULL) 11071 { 11072 11073 /* To some extent make sure that we are dealing with a list from 11074 * "getmatches()". */ 11075 li = l->lv_first; 11076 while (li != NULL) 11077 { 11078 if (li->li_tv.v_type != VAR_DICT 11079 || (d = li->li_tv.vval.v_dict) == NULL) 11080 { 11081 emsg(_(e_invarg)); 11082 return; 11083 } 11084 if (!(dict_find(d, (char_u *)"group", -1) != NULL 11085 && (dict_find(d, (char_u *)"pattern", -1) != NULL 11086 || dict_find(d, (char_u *)"pos1", -1) != NULL) 11087 && dict_find(d, (char_u *)"priority", -1) != NULL 11088 && dict_find(d, (char_u *)"id", -1) != NULL)) 11089 { 11090 emsg(_(e_invarg)); 11091 return; 11092 } 11093 li = li->li_next; 11094 } 11095 11096 clear_matches(curwin); 11097 li = l->lv_first; 11098 while (li != NULL) 11099 { 11100 int i = 0; 11101 char_u buf[5]; 11102 dictitem_T *di; 11103 char_u *group; 11104 int priority; 11105 int id; 11106 char_u *conceal; 11107 11108 d = li->li_tv.vval.v_dict; 11109 if (dict_find(d, (char_u *)"pattern", -1) == NULL) 11110 { 11111 if (s == NULL) 11112 { 11113 s = list_alloc(); 11114 if (s == NULL) 11115 return; 11116 } 11117 11118 /* match from matchaddpos() */ 11119 for (i = 1; i < 9; i++) 11120 { 11121 sprintf((char *)buf, (char *)"pos%d", i); 11122 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL) 11123 { 11124 if (di->di_tv.v_type != VAR_LIST) 11125 return; 11126 11127 list_append_tv(s, &di->di_tv); 11128 s->lv_refcount++; 11129 } 11130 else 11131 break; 11132 } 11133 } 11134 11135 group = dict_get_string(d, (char_u *)"group", TRUE); 11136 priority = (int)dict_get_number(d, (char_u *)"priority"); 11137 id = (int)dict_get_number(d, (char_u *)"id"); 11138 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL 11139 ? dict_get_string(d, (char_u *)"conceal", TRUE) 11140 : NULL; 11141 if (i == 0) 11142 { 11143 match_add(curwin, group, 11144 dict_get_string(d, (char_u *)"pattern", FALSE), 11145 priority, id, NULL, conceal); 11146 } 11147 else 11148 { 11149 match_add(curwin, group, NULL, priority, id, s, conceal); 11150 list_unref(s); 11151 s = NULL; 11152 } 11153 vim_free(group); 11154 vim_free(conceal); 11155 11156 li = li->li_next; 11157 } 11158 rettv->vval.v_number = 0; 11159 } 11160 #endif 11161 } 11162 11163 /* 11164 * "setpos()" function 11165 */ 11166 static void 11167 f_setpos(typval_T *argvars, typval_T *rettv) 11168 { 11169 pos_T pos; 11170 int fnum; 11171 char_u *name; 11172 colnr_T curswant = -1; 11173 11174 rettv->vval.v_number = -1; 11175 name = tv_get_string_chk(argvars); 11176 if (name != NULL) 11177 { 11178 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK) 11179 { 11180 if (--pos.col < 0) 11181 pos.col = 0; 11182 if (name[0] == '.' && name[1] == NUL) 11183 { 11184 /* set cursor; "fnum" is ignored */ 11185 curwin->w_cursor = pos; 11186 if (curswant >= 0) 11187 { 11188 curwin->w_curswant = curswant - 1; 11189 curwin->w_set_curswant = FALSE; 11190 } 11191 check_cursor(); 11192 rettv->vval.v_number = 0; 11193 } 11194 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) 11195 { 11196 /* set mark */ 11197 if (setmark_pos(name[1], &pos, fnum) == OK) 11198 rettv->vval.v_number = 0; 11199 } 11200 else 11201 emsg(_(e_invarg)); 11202 } 11203 } 11204 } 11205 11206 /* 11207 * "setqflist()" function 11208 */ 11209 static void 11210 f_setqflist(typval_T *argvars, typval_T *rettv) 11211 { 11212 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv); 11213 } 11214 11215 /* 11216 * "setreg()" function 11217 */ 11218 static void 11219 f_setreg(typval_T *argvars, typval_T *rettv) 11220 { 11221 int regname; 11222 char_u *strregname; 11223 char_u *stropt; 11224 char_u *strval; 11225 int append; 11226 char_u yank_type; 11227 long block_len; 11228 11229 block_len = -1; 11230 yank_type = MAUTO; 11231 append = FALSE; 11232 11233 strregname = tv_get_string_chk(argvars); 11234 rettv->vval.v_number = 1; /* FAIL is default */ 11235 11236 if (strregname == NULL) 11237 return; /* type error; errmsg already given */ 11238 regname = *strregname; 11239 if (regname == 0 || regname == '@') 11240 regname = '"'; 11241 11242 if (argvars[2].v_type != VAR_UNKNOWN) 11243 { 11244 stropt = tv_get_string_chk(&argvars[2]); 11245 if (stropt == NULL) 11246 return; /* type error */ 11247 for (; *stropt != NUL; ++stropt) 11248 switch (*stropt) 11249 { 11250 case 'a': case 'A': /* append */ 11251 append = TRUE; 11252 break; 11253 case 'v': case 'c': /* character-wise selection */ 11254 yank_type = MCHAR; 11255 break; 11256 case 'V': case 'l': /* line-wise selection */ 11257 yank_type = MLINE; 11258 break; 11259 case 'b': case Ctrl_V: /* block-wise selection */ 11260 yank_type = MBLOCK; 11261 if (VIM_ISDIGIT(stropt[1])) 11262 { 11263 ++stropt; 11264 block_len = getdigits(&stropt) - 1; 11265 --stropt; 11266 } 11267 break; 11268 } 11269 } 11270 11271 if (argvars[1].v_type == VAR_LIST) 11272 { 11273 char_u **lstval; 11274 char_u **allocval; 11275 char_u buf[NUMBUFLEN]; 11276 char_u **curval; 11277 char_u **curallocval; 11278 list_T *ll = argvars[1].vval.v_list; 11279 listitem_T *li; 11280 int len; 11281 11282 /* If the list is NULL handle like an empty list. */ 11283 len = ll == NULL ? 0 : ll->lv_len; 11284 11285 /* First half: use for pointers to result lines; second half: use for 11286 * pointers to allocated copies. */ 11287 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2)); 11288 if (lstval == NULL) 11289 return; 11290 curval = lstval; 11291 allocval = lstval + len + 2; 11292 curallocval = allocval; 11293 11294 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL; 11295 li = li->li_next) 11296 { 11297 strval = tv_get_string_buf_chk(&li->li_tv, buf); 11298 if (strval == NULL) 11299 goto free_lstval; 11300 if (strval == buf) 11301 { 11302 /* Need to make a copy, next tv_get_string_buf_chk() will 11303 * overwrite the string. */ 11304 strval = vim_strsave(buf); 11305 if (strval == NULL) 11306 goto free_lstval; 11307 *curallocval++ = strval; 11308 } 11309 *curval++ = strval; 11310 } 11311 *curval++ = NULL; 11312 11313 write_reg_contents_lst(regname, lstval, -1, 11314 append, yank_type, block_len); 11315 free_lstval: 11316 while (curallocval > allocval) 11317 vim_free(*--curallocval); 11318 vim_free(lstval); 11319 } 11320 else 11321 { 11322 strval = tv_get_string_chk(&argvars[1]); 11323 if (strval == NULL) 11324 return; 11325 write_reg_contents_ex(regname, strval, -1, 11326 append, yank_type, block_len); 11327 } 11328 rettv->vval.v_number = 0; 11329 } 11330 11331 /* 11332 * "settabvar()" function 11333 */ 11334 static void 11335 f_settabvar(typval_T *argvars, typval_T *rettv) 11336 { 11337 tabpage_T *save_curtab; 11338 tabpage_T *tp; 11339 char_u *varname, *tabvarname; 11340 typval_T *varp; 11341 11342 rettv->vval.v_number = 0; 11343 11344 if (check_restricted() || check_secure()) 11345 return; 11346 11347 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL)); 11348 varname = tv_get_string_chk(&argvars[1]); 11349 varp = &argvars[2]; 11350 11351 if (varname != NULL && varp != NULL && tp != NULL) 11352 { 11353 save_curtab = curtab; 11354 goto_tabpage_tp(tp, FALSE, FALSE); 11355 11356 tabvarname = alloc((unsigned)STRLEN(varname) + 3); 11357 if (tabvarname != NULL) 11358 { 11359 STRCPY(tabvarname, "t:"); 11360 STRCPY(tabvarname + 2, varname); 11361 set_var(tabvarname, varp, TRUE); 11362 vim_free(tabvarname); 11363 } 11364 11365 /* Restore current tabpage */ 11366 if (valid_tabpage(save_curtab)) 11367 goto_tabpage_tp(save_curtab, FALSE, FALSE); 11368 } 11369 } 11370 11371 /* 11372 * "settabwinvar()" function 11373 */ 11374 static void 11375 f_settabwinvar(typval_T *argvars, typval_T *rettv) 11376 { 11377 setwinvar(argvars, rettv, 1); 11378 } 11379 11380 /* 11381 * "settagstack()" function 11382 */ 11383 static void 11384 f_settagstack(typval_T *argvars, typval_T *rettv) 11385 { 11386 static char *e_invact2 = N_("E962: Invalid action: '%s'"); 11387 win_T *wp; 11388 dict_T *d; 11389 int action = 'r'; 11390 11391 rettv->vval.v_number = -1; 11392 11393 // first argument: window number or id 11394 wp = find_win_by_nr_or_id(&argvars[0]); 11395 if (wp == NULL) 11396 return; 11397 11398 // second argument: dict with items to set in the tag stack 11399 if (argvars[1].v_type != VAR_DICT) 11400 { 11401 emsg(_(e_dictreq)); 11402 return; 11403 } 11404 d = argvars[1].vval.v_dict; 11405 if (d == NULL) 11406 return; 11407 11408 // third argument: action - 'a' for append and 'r' for replace. 11409 // default is to replace the stack. 11410 if (argvars[2].v_type == VAR_UNKNOWN) 11411 action = 'r'; 11412 else if (argvars[2].v_type == VAR_STRING) 11413 { 11414 char_u *actstr; 11415 actstr = tv_get_string_chk(&argvars[2]); 11416 if (actstr == NULL) 11417 return; 11418 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL) 11419 action = *actstr; 11420 else 11421 { 11422 semsg(_(e_invact2), actstr); 11423 return; 11424 } 11425 } 11426 else 11427 { 11428 emsg(_(e_stringreq)); 11429 return; 11430 } 11431 11432 if (set_tagstack(wp, d, action) == OK) 11433 rettv->vval.v_number = 0; 11434 } 11435 11436 /* 11437 * "setwinvar()" function 11438 */ 11439 static void 11440 f_setwinvar(typval_T *argvars, typval_T *rettv) 11441 { 11442 setwinvar(argvars, rettv, 0); 11443 } 11444 11445 #ifdef FEAT_CRYPT 11446 /* 11447 * "sha256({string})" function 11448 */ 11449 static void 11450 f_sha256(typval_T *argvars, typval_T *rettv) 11451 { 11452 char_u *p; 11453 11454 p = tv_get_string(&argvars[0]); 11455 rettv->vval.v_string = vim_strsave( 11456 sha256_bytes(p, (int)STRLEN(p), NULL, 0)); 11457 rettv->v_type = VAR_STRING; 11458 } 11459 #endif /* FEAT_CRYPT */ 11460 11461 /* 11462 * "shellescape({string})" function 11463 */ 11464 static void 11465 f_shellescape(typval_T *argvars, typval_T *rettv) 11466 { 11467 int do_special = non_zero_arg(&argvars[1]); 11468 11469 rettv->vval.v_string = vim_strsave_shellescape( 11470 tv_get_string(&argvars[0]), do_special, do_special); 11471 rettv->v_type = VAR_STRING; 11472 } 11473 11474 /* 11475 * shiftwidth() function 11476 */ 11477 static void 11478 f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv) 11479 { 11480 rettv->vval.v_number = 0; 11481 11482 if (argvars[0].v_type != VAR_UNKNOWN) 11483 { 11484 long col; 11485 11486 col = (long)tv_get_number_chk(argvars, NULL); 11487 if (col < 0) 11488 return; // type error; errmsg already given 11489 #ifdef FEAT_VARTABS 11490 rettv->vval.v_number = get_sw_value_col(curbuf, col); 11491 return; 11492 #endif 11493 } 11494 11495 rettv->vval.v_number = get_sw_value(curbuf); 11496 } 11497 11498 #ifdef FEAT_SIGNS 11499 /* 11500 * "sign_define()" function 11501 */ 11502 static void 11503 f_sign_define(typval_T *argvars, typval_T *rettv) 11504 { 11505 char_u *name; 11506 dict_T *dict; 11507 char_u *icon = NULL; 11508 char_u *linehl = NULL; 11509 char_u *text = NULL; 11510 char_u *texthl = NULL; 11511 11512 rettv->vval.v_number = -1; 11513 11514 name = tv_get_string_chk(&argvars[0]); 11515 if (name == NULL) 11516 return; 11517 11518 if (argvars[1].v_type != VAR_UNKNOWN) 11519 { 11520 if (argvars[1].v_type != VAR_DICT) 11521 { 11522 emsg(_(e_dictreq)); 11523 return; 11524 } 11525 11526 // sign attributes 11527 dict = argvars[1].vval.v_dict; 11528 if (dict_find(dict, (char_u *)"icon", -1) != NULL) 11529 icon = dict_get_string(dict, (char_u *)"icon", TRUE); 11530 if (dict_find(dict, (char_u *)"linehl", -1) != NULL) 11531 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE); 11532 if (dict_find(dict, (char_u *)"text", -1) != NULL) 11533 text = dict_get_string(dict, (char_u *)"text", TRUE); 11534 if (dict_find(dict, (char_u *)"texthl", -1) != NULL) 11535 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE); 11536 } 11537 11538 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK) 11539 rettv->vval.v_number = 0; 11540 11541 vim_free(icon); 11542 vim_free(linehl); 11543 vim_free(text); 11544 vim_free(texthl); 11545 } 11546 11547 /* 11548 * "sign_getdefined()" function 11549 */ 11550 static void 11551 f_sign_getdefined(typval_T *argvars, typval_T *rettv) 11552 { 11553 char_u *name = NULL; 11554 11555 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK) 11556 return; 11557 11558 if (argvars[0].v_type != VAR_UNKNOWN) 11559 name = tv_get_string(&argvars[0]); 11560 11561 sign_getlist(name, rettv->vval.v_list); 11562 } 11563 11564 /* 11565 * "sign_getplaced()" function 11566 */ 11567 static void 11568 f_sign_getplaced(typval_T *argvars, typval_T *rettv) 11569 { 11570 buf_T *buf = NULL; 11571 dict_T *dict; 11572 dictitem_T *di; 11573 linenr_T lnum = 0; 11574 int sign_id = 0; 11575 char_u *group = NULL; 11576 int notanum = FALSE; 11577 11578 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK) 11579 return; 11580 11581 if (argvars[0].v_type != VAR_UNKNOWN) 11582 { 11583 // get signs placed in the specified buffer 11584 buf = get_buf_arg(&argvars[0]); 11585 if (buf == NULL) 11586 return; 11587 11588 if (argvars[1].v_type != VAR_UNKNOWN) 11589 { 11590 if (argvars[1].v_type != VAR_DICT || 11591 ((dict = argvars[1].vval.v_dict) == NULL)) 11592 { 11593 emsg(_(e_dictreq)); 11594 return; 11595 } 11596 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL) 11597 { 11598 // get signs placed at this line 11599 (void)tv_get_number_chk(&di->di_tv, ¬anum); 11600 if (notanum) 11601 return; 11602 lnum = tv_get_lnum(&di->di_tv); 11603 } 11604 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL) 11605 { 11606 // get sign placed with this identifier 11607 sign_id = (int)tv_get_number_chk(&di->di_tv, ¬anum); 11608 if (notanum) 11609 return; 11610 } 11611 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL) 11612 { 11613 group = tv_get_string_chk(&di->di_tv); 11614 if (group == NULL) 11615 return; 11616 if (*group == '\0') // empty string means global group 11617 group = NULL; 11618 } 11619 } 11620 } 11621 11622 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list); 11623 } 11624 11625 /* 11626 * "sign_jump()" function 11627 */ 11628 static void 11629 f_sign_jump(typval_T *argvars, typval_T *rettv) 11630 { 11631 int sign_id; 11632 char_u *sign_group = NULL; 11633 buf_T *buf; 11634 int notanum = FALSE; 11635 11636 rettv->vval.v_number = -1; 11637 11638 // Sign identifer 11639 sign_id = (int)tv_get_number_chk(&argvars[0], ¬anum); 11640 if (notanum) 11641 return; 11642 if (sign_id <= 0) 11643 { 11644 emsg(_(e_invarg)); 11645 return; 11646 } 11647 11648 // Sign group 11649 sign_group = tv_get_string_chk(&argvars[1]); 11650 if (sign_group == NULL) 11651 return; 11652 if (sign_group[0] == '\0') 11653 sign_group = NULL; // global sign group 11654 else 11655 { 11656 sign_group = vim_strsave(sign_group); 11657 if (sign_group == NULL) 11658 return; 11659 } 11660 11661 // Buffer to place the sign 11662 buf = get_buf_arg(&argvars[2]); 11663 if (buf == NULL) 11664 goto cleanup; 11665 11666 rettv->vval.v_number = sign_jump(sign_id, sign_group, buf); 11667 11668 cleanup: 11669 vim_free(sign_group); 11670 } 11671 11672 /* 11673 * "sign_place()" function 11674 */ 11675 static void 11676 f_sign_place(typval_T *argvars, typval_T *rettv) 11677 { 11678 int sign_id; 11679 char_u *group = NULL; 11680 char_u *sign_name; 11681 buf_T *buf; 11682 dict_T *dict; 11683 dictitem_T *di; 11684 linenr_T lnum = 0; 11685 int prio = SIGN_DEF_PRIO; 11686 int notanum = FALSE; 11687 11688 rettv->vval.v_number = -1; 11689 11690 // Sign identifer 11691 sign_id = (int)tv_get_number_chk(&argvars[0], ¬anum); 11692 if (notanum) 11693 return; 11694 if (sign_id < 0) 11695 { 11696 emsg(_(e_invarg)); 11697 return; 11698 } 11699 11700 // Sign group 11701 group = tv_get_string_chk(&argvars[1]); 11702 if (group == NULL) 11703 return; 11704 if (group[0] == '\0') 11705 group = NULL; // global sign group 11706 else 11707 { 11708 group = vim_strsave(group); 11709 if (group == NULL) 11710 return; 11711 } 11712 11713 // Sign name 11714 sign_name = tv_get_string_chk(&argvars[2]); 11715 if (sign_name == NULL) 11716 goto cleanup; 11717 11718 // Buffer to place the sign 11719 buf = get_buf_arg(&argvars[3]); 11720 if (buf == NULL) 11721 goto cleanup; 11722 11723 if (argvars[4].v_type != VAR_UNKNOWN) 11724 { 11725 if (argvars[4].v_type != VAR_DICT || 11726 ((dict = argvars[4].vval.v_dict) == NULL)) 11727 { 11728 emsg(_(e_dictreq)); 11729 goto cleanup; 11730 } 11731 11732 // Line number where the sign is to be placed 11733 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL) 11734 { 11735 (void)tv_get_number_chk(&di->di_tv, ¬anum); 11736 if (notanum) 11737 goto cleanup; 11738 lnum = tv_get_lnum(&di->di_tv); 11739 } 11740 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL) 11741 { 11742 // Sign priority 11743 prio = (int)tv_get_number_chk(&di->di_tv, ¬anum); 11744 if (notanum) 11745 goto cleanup; 11746 } 11747 } 11748 11749 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK) 11750 rettv->vval.v_number = sign_id; 11751 11752 cleanup: 11753 vim_free(group); 11754 } 11755 11756 /* 11757 * "sign_undefine()" function 11758 */ 11759 static void 11760 f_sign_undefine(typval_T *argvars, typval_T *rettv) 11761 { 11762 char_u *name; 11763 11764 rettv->vval.v_number = -1; 11765 11766 if (argvars[0].v_type == VAR_UNKNOWN) 11767 { 11768 // Free all the signs 11769 free_signs(); 11770 rettv->vval.v_number = 0; 11771 } 11772 else 11773 { 11774 // Free only the specified sign 11775 name = tv_get_string_chk(&argvars[0]); 11776 if (name == NULL) 11777 return; 11778 11779 if (sign_undefine_by_name(name) == OK) 11780 rettv->vval.v_number = 0; 11781 } 11782 } 11783 11784 /* 11785 * "sign_unplace()" function 11786 */ 11787 static void 11788 f_sign_unplace(typval_T *argvars, typval_T *rettv) 11789 { 11790 dict_T *dict; 11791 dictitem_T *di; 11792 int sign_id = 0; 11793 buf_T *buf = NULL; 11794 char_u *group = NULL; 11795 11796 rettv->vval.v_number = -1; 11797 11798 if (argvars[0].v_type != VAR_STRING) 11799 { 11800 emsg(_(e_invarg)); 11801 return; 11802 } 11803 11804 group = tv_get_string(&argvars[0]); 11805 if (group[0] == '\0') 11806 group = NULL; // global sign group 11807 else 11808 { 11809 group = vim_strsave(group); 11810 if (group == NULL) 11811 return; 11812 } 11813 11814 if (argvars[1].v_type != VAR_UNKNOWN) 11815 { 11816 if (argvars[1].v_type != VAR_DICT) 11817 { 11818 emsg(_(e_dictreq)); 11819 goto cleanup; 11820 } 11821 dict = argvars[1].vval.v_dict; 11822 11823 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL) 11824 { 11825 buf = get_buf_arg(&di->di_tv); 11826 if (buf == NULL) 11827 goto cleanup; 11828 } 11829 if (dict_find(dict, (char_u *)"id", -1) != NULL) 11830 sign_id = dict_get_number(dict, (char_u *)"id"); 11831 } 11832 11833 if (buf == NULL) 11834 { 11835 // Delete the sign in all the buffers 11836 FOR_ALL_BUFFERS(buf) 11837 if (sign_unplace(sign_id, group, buf, 0) == OK) 11838 rettv->vval.v_number = 0; 11839 } 11840 else 11841 { 11842 if (sign_unplace(sign_id, group, buf, 0) == OK) 11843 rettv->vval.v_number = 0; 11844 } 11845 11846 cleanup: 11847 vim_free(group); 11848 } 11849 #endif 11850 11851 /* 11852 * "simplify()" function 11853 */ 11854 static void 11855 f_simplify(typval_T *argvars, typval_T *rettv) 11856 { 11857 char_u *p; 11858 11859 p = tv_get_string(&argvars[0]); 11860 rettv->vval.v_string = vim_strsave(p); 11861 simplify_filename(rettv->vval.v_string); /* simplify in place */ 11862 rettv->v_type = VAR_STRING; 11863 } 11864 11865 #ifdef FEAT_FLOAT 11866 /* 11867 * "sin()" function 11868 */ 11869 static void 11870 f_sin(typval_T *argvars, typval_T *rettv) 11871 { 11872 float_T f = 0.0; 11873 11874 rettv->v_type = VAR_FLOAT; 11875 if (get_float_arg(argvars, &f) == OK) 11876 rettv->vval.v_float = sin(f); 11877 else 11878 rettv->vval.v_float = 0.0; 11879 } 11880 11881 /* 11882 * "sinh()" function 11883 */ 11884 static void 11885 f_sinh(typval_T *argvars, typval_T *rettv) 11886 { 11887 float_T f = 0.0; 11888 11889 rettv->v_type = VAR_FLOAT; 11890 if (get_float_arg(argvars, &f) == OK) 11891 rettv->vval.v_float = sinh(f); 11892 else 11893 rettv->vval.v_float = 0.0; 11894 } 11895 #endif 11896 11897 static int 11898 #ifdef __BORLANDC__ 11899 _RTLENTRYF 11900 #endif 11901 item_compare(const void *s1, const void *s2); 11902 static int 11903 #ifdef __BORLANDC__ 11904 _RTLENTRYF 11905 #endif 11906 item_compare2(const void *s1, const void *s2); 11907 11908 /* struct used in the array that's given to qsort() */ 11909 typedef struct 11910 { 11911 listitem_T *item; 11912 int idx; 11913 } sortItem_T; 11914 11915 /* struct storing information about current sort */ 11916 typedef struct 11917 { 11918 int item_compare_ic; 11919 int item_compare_numeric; 11920 int item_compare_numbers; 11921 #ifdef FEAT_FLOAT 11922 int item_compare_float; 11923 #endif 11924 char_u *item_compare_func; 11925 partial_T *item_compare_partial; 11926 dict_T *item_compare_selfdict; 11927 int item_compare_func_err; 11928 int item_compare_keep_zero; 11929 } sortinfo_T; 11930 static sortinfo_T *sortinfo = NULL; 11931 #define ITEM_COMPARE_FAIL 999 11932 11933 /* 11934 * Compare functions for f_sort() and f_uniq() below. 11935 */ 11936 static int 11937 #ifdef __BORLANDC__ 11938 _RTLENTRYF 11939 #endif 11940 item_compare(const void *s1, const void *s2) 11941 { 11942 sortItem_T *si1, *si2; 11943 typval_T *tv1, *tv2; 11944 char_u *p1, *p2; 11945 char_u *tofree1 = NULL, *tofree2 = NULL; 11946 int res; 11947 char_u numbuf1[NUMBUFLEN]; 11948 char_u numbuf2[NUMBUFLEN]; 11949 11950 si1 = (sortItem_T *)s1; 11951 si2 = (sortItem_T *)s2; 11952 tv1 = &si1->item->li_tv; 11953 tv2 = &si2->item->li_tv; 11954 11955 if (sortinfo->item_compare_numbers) 11956 { 11957 varnumber_T v1 = tv_get_number(tv1); 11958 varnumber_T v2 = tv_get_number(tv2); 11959 11960 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; 11961 } 11962 11963 #ifdef FEAT_FLOAT 11964 if (sortinfo->item_compare_float) 11965 { 11966 float_T v1 = tv_get_float(tv1); 11967 float_T v2 = tv_get_float(tv2); 11968 11969 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; 11970 } 11971 #endif 11972 11973 /* tv2string() puts quotes around a string and allocates memory. Don't do 11974 * that for string variables. Use a single quote when comparing with a 11975 * non-string to do what the docs promise. */ 11976 if (tv1->v_type == VAR_STRING) 11977 { 11978 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) 11979 p1 = (char_u *)"'"; 11980 else 11981 p1 = tv1->vval.v_string; 11982 } 11983 else 11984 p1 = tv2string(tv1, &tofree1, numbuf1, 0); 11985 if (tv2->v_type == VAR_STRING) 11986 { 11987 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) 11988 p2 = (char_u *)"'"; 11989 else 11990 p2 = tv2->vval.v_string; 11991 } 11992 else 11993 p2 = tv2string(tv2, &tofree2, numbuf2, 0); 11994 if (p1 == NULL) 11995 p1 = (char_u *)""; 11996 if (p2 == NULL) 11997 p2 = (char_u *)""; 11998 if (!sortinfo->item_compare_numeric) 11999 { 12000 if (sortinfo->item_compare_ic) 12001 res = STRICMP(p1, p2); 12002 else 12003 res = STRCMP(p1, p2); 12004 } 12005 else 12006 { 12007 double n1, n2; 12008 n1 = strtod((char *)p1, (char **)&p1); 12009 n2 = strtod((char *)p2, (char **)&p2); 12010 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1; 12011 } 12012 12013 /* When the result would be zero, compare the item indexes. Makes the 12014 * sort stable. */ 12015 if (res == 0 && !sortinfo->item_compare_keep_zero) 12016 res = si1->idx > si2->idx ? 1 : -1; 12017 12018 vim_free(tofree1); 12019 vim_free(tofree2); 12020 return res; 12021 } 12022 12023 static int 12024 #ifdef __BORLANDC__ 12025 _RTLENTRYF 12026 #endif 12027 item_compare2(const void *s1, const void *s2) 12028 { 12029 sortItem_T *si1, *si2; 12030 int res; 12031 typval_T rettv; 12032 typval_T argv[3]; 12033 int dummy; 12034 char_u *func_name; 12035 partial_T *partial = sortinfo->item_compare_partial; 12036 12037 /* shortcut after failure in previous call; compare all items equal */ 12038 if (sortinfo->item_compare_func_err) 12039 return 0; 12040 12041 si1 = (sortItem_T *)s1; 12042 si2 = (sortItem_T *)s2; 12043 12044 if (partial == NULL) 12045 func_name = sortinfo->item_compare_func; 12046 else 12047 func_name = partial_name(partial); 12048 12049 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED 12050 * in the copy without changing the original list items. */ 12051 copy_tv(&si1->item->li_tv, &argv[0]); 12052 copy_tv(&si2->item->li_tv, &argv[1]); 12053 12054 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */ 12055 res = call_func(func_name, (int)STRLEN(func_name), 12056 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, 12057 partial, sortinfo->item_compare_selfdict); 12058 clear_tv(&argv[0]); 12059 clear_tv(&argv[1]); 12060 12061 if (res == FAIL) 12062 res = ITEM_COMPARE_FAIL; 12063 else 12064 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err); 12065 if (sortinfo->item_compare_func_err) 12066 res = ITEM_COMPARE_FAIL; /* return value has wrong type */ 12067 clear_tv(&rettv); 12068 12069 /* When the result would be zero, compare the pointers themselves. Makes 12070 * the sort stable. */ 12071 if (res == 0 && !sortinfo->item_compare_keep_zero) 12072 res = si1->idx > si2->idx ? 1 : -1; 12073 12074 return res; 12075 } 12076 12077 /* 12078 * "sort({list})" function 12079 */ 12080 static void 12081 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) 12082 { 12083 list_T *l; 12084 listitem_T *li; 12085 sortItem_T *ptrs; 12086 sortinfo_T *old_sortinfo; 12087 sortinfo_T info; 12088 long len; 12089 long i; 12090 12091 /* Pointer to current info struct used in compare function. Save and 12092 * restore the current one for nested calls. */ 12093 old_sortinfo = sortinfo; 12094 sortinfo = &info; 12095 12096 if (argvars[0].v_type != VAR_LIST) 12097 semsg(_(e_listarg), sort ? "sort()" : "uniq()"); 12098 else 12099 { 12100 l = argvars[0].vval.v_list; 12101 if (l == NULL || tv_check_lock(l->lv_lock, 12102 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")), 12103 TRUE)) 12104 goto theend; 12105 rettv_list_set(rettv, l); 12106 12107 len = list_len(l); 12108 if (len <= 1) 12109 goto theend; /* short list sorts pretty quickly */ 12110 12111 info.item_compare_ic = FALSE; 12112 info.item_compare_numeric = FALSE; 12113 info.item_compare_numbers = FALSE; 12114 #ifdef FEAT_FLOAT 12115 info.item_compare_float = FALSE; 12116 #endif 12117 info.item_compare_func = NULL; 12118 info.item_compare_partial = NULL; 12119 info.item_compare_selfdict = NULL; 12120 if (argvars[1].v_type != VAR_UNKNOWN) 12121 { 12122 /* optional second argument: {func} */ 12123 if (argvars[1].v_type == VAR_FUNC) 12124 info.item_compare_func = argvars[1].vval.v_string; 12125 else if (argvars[1].v_type == VAR_PARTIAL) 12126 info.item_compare_partial = argvars[1].vval.v_partial; 12127 else 12128 { 12129 int error = FALSE; 12130 12131 i = (long)tv_get_number_chk(&argvars[1], &error); 12132 if (error) 12133 goto theend; /* type error; errmsg already given */ 12134 if (i == 1) 12135 info.item_compare_ic = TRUE; 12136 else if (argvars[1].v_type != VAR_NUMBER) 12137 info.item_compare_func = tv_get_string(&argvars[1]); 12138 else if (i != 0) 12139 { 12140 emsg(_(e_invarg)); 12141 goto theend; 12142 } 12143 if (info.item_compare_func != NULL) 12144 { 12145 if (*info.item_compare_func == NUL) 12146 { 12147 /* empty string means default sort */ 12148 info.item_compare_func = NULL; 12149 } 12150 else if (STRCMP(info.item_compare_func, "n") == 0) 12151 { 12152 info.item_compare_func = NULL; 12153 info.item_compare_numeric = TRUE; 12154 } 12155 else if (STRCMP(info.item_compare_func, "N") == 0) 12156 { 12157 info.item_compare_func = NULL; 12158 info.item_compare_numbers = TRUE; 12159 } 12160 #ifdef FEAT_FLOAT 12161 else if (STRCMP(info.item_compare_func, "f") == 0) 12162 { 12163 info.item_compare_func = NULL; 12164 info.item_compare_float = TRUE; 12165 } 12166 #endif 12167 else if (STRCMP(info.item_compare_func, "i") == 0) 12168 { 12169 info.item_compare_func = NULL; 12170 info.item_compare_ic = TRUE; 12171 } 12172 } 12173 } 12174 12175 if (argvars[2].v_type != VAR_UNKNOWN) 12176 { 12177 /* optional third argument: {dict} */ 12178 if (argvars[2].v_type != VAR_DICT) 12179 { 12180 emsg(_(e_dictreq)); 12181 goto theend; 12182 } 12183 info.item_compare_selfdict = argvars[2].vval.v_dict; 12184 } 12185 } 12186 12187 /* Make an array with each entry pointing to an item in the List. */ 12188 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T))); 12189 if (ptrs == NULL) 12190 goto theend; 12191 12192 i = 0; 12193 if (sort) 12194 { 12195 /* sort(): ptrs will be the list to sort */ 12196 for (li = l->lv_first; li != NULL; li = li->li_next) 12197 { 12198 ptrs[i].item = li; 12199 ptrs[i].idx = i; 12200 ++i; 12201 } 12202 12203 info.item_compare_func_err = FALSE; 12204 info.item_compare_keep_zero = FALSE; 12205 /* test the compare function */ 12206 if ((info.item_compare_func != NULL 12207 || info.item_compare_partial != NULL) 12208 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1]) 12209 == ITEM_COMPARE_FAIL) 12210 emsg(_("E702: Sort compare function failed")); 12211 else 12212 { 12213 /* Sort the array with item pointers. */ 12214 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T), 12215 info.item_compare_func == NULL 12216 && info.item_compare_partial == NULL 12217 ? item_compare : item_compare2); 12218 12219 if (!info.item_compare_func_err) 12220 { 12221 /* Clear the List and append the items in sorted order. */ 12222 l->lv_first = l->lv_last = l->lv_idx_item = NULL; 12223 l->lv_len = 0; 12224 for (i = 0; i < len; ++i) 12225 list_append(l, ptrs[i].item); 12226 } 12227 } 12228 } 12229 else 12230 { 12231 int (*item_compare_func_ptr)(const void *, const void *); 12232 12233 /* f_uniq(): ptrs will be a stack of items to remove */ 12234 info.item_compare_func_err = FALSE; 12235 info.item_compare_keep_zero = TRUE; 12236 item_compare_func_ptr = info.item_compare_func != NULL 12237 || info.item_compare_partial != NULL 12238 ? item_compare2 : item_compare; 12239 12240 for (li = l->lv_first; li != NULL && li->li_next != NULL; 12241 li = li->li_next) 12242 { 12243 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next) 12244 == 0) 12245 ptrs[i++].item = li; 12246 if (info.item_compare_func_err) 12247 { 12248 emsg(_("E882: Uniq compare function failed")); 12249 break; 12250 } 12251 } 12252 12253 if (!info.item_compare_func_err) 12254 { 12255 while (--i >= 0) 12256 { 12257 li = ptrs[i].item->li_next; 12258 ptrs[i].item->li_next = li->li_next; 12259 if (li->li_next != NULL) 12260 li->li_next->li_prev = ptrs[i].item; 12261 else 12262 l->lv_last = ptrs[i].item; 12263 list_fix_watch(l, li); 12264 listitem_free(li); 12265 l->lv_len--; 12266 } 12267 } 12268 } 12269 12270 vim_free(ptrs); 12271 } 12272 theend: 12273 sortinfo = old_sortinfo; 12274 } 12275 12276 /* 12277 * "sort({list})" function 12278 */ 12279 static void 12280 f_sort(typval_T *argvars, typval_T *rettv) 12281 { 12282 do_sort_uniq(argvars, rettv, TRUE); 12283 } 12284 12285 /* 12286 * "uniq({list})" function 12287 */ 12288 static void 12289 f_uniq(typval_T *argvars, typval_T *rettv) 12290 { 12291 do_sort_uniq(argvars, rettv, FALSE); 12292 } 12293 12294 /* 12295 * "soundfold({word})" function 12296 */ 12297 static void 12298 f_soundfold(typval_T *argvars, typval_T *rettv) 12299 { 12300 char_u *s; 12301 12302 rettv->v_type = VAR_STRING; 12303 s = tv_get_string(&argvars[0]); 12304 #ifdef FEAT_SPELL 12305 rettv->vval.v_string = eval_soundfold(s); 12306 #else 12307 rettv->vval.v_string = vim_strsave(s); 12308 #endif 12309 } 12310 12311 /* 12312 * "spellbadword()" function 12313 */ 12314 static void 12315 f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv) 12316 { 12317 char_u *word = (char_u *)""; 12318 hlf_T attr = HLF_COUNT; 12319 int len = 0; 12320 12321 if (rettv_list_alloc(rettv) == FAIL) 12322 return; 12323 12324 #ifdef FEAT_SPELL 12325 if (argvars[0].v_type == VAR_UNKNOWN) 12326 { 12327 /* Find the start and length of the badly spelled word. */ 12328 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr); 12329 if (len != 0) 12330 { 12331 word = ml_get_cursor(); 12332 curwin->w_set_curswant = TRUE; 12333 } 12334 } 12335 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL) 12336 { 12337 char_u *str = tv_get_string_chk(&argvars[0]); 12338 int capcol = -1; 12339 12340 if (str != NULL) 12341 { 12342 /* Check the argument for spelling. */ 12343 while (*str != NUL) 12344 { 12345 len = spell_check(curwin, str, &attr, &capcol, FALSE); 12346 if (attr != HLF_COUNT) 12347 { 12348 word = str; 12349 break; 12350 } 12351 str += len; 12352 capcol -= len; 12353 } 12354 } 12355 } 12356 #endif 12357 12358 list_append_string(rettv->vval.v_list, word, len); 12359 list_append_string(rettv->vval.v_list, (char_u *)( 12360 attr == HLF_SPB ? "bad" : 12361 attr == HLF_SPR ? "rare" : 12362 attr == HLF_SPL ? "local" : 12363 attr == HLF_SPC ? "caps" : 12364 ""), -1); 12365 } 12366 12367 /* 12368 * "spellsuggest()" function 12369 */ 12370 static void 12371 f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv) 12372 { 12373 #ifdef FEAT_SPELL 12374 char_u *str; 12375 int typeerr = FALSE; 12376 int maxcount; 12377 garray_T ga; 12378 int i; 12379 listitem_T *li; 12380 int need_capital = FALSE; 12381 #endif 12382 12383 if (rettv_list_alloc(rettv) == FAIL) 12384 return; 12385 12386 #ifdef FEAT_SPELL 12387 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) 12388 { 12389 str = tv_get_string(&argvars[0]); 12390 if (argvars[1].v_type != VAR_UNKNOWN) 12391 { 12392 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr); 12393 if (maxcount <= 0) 12394 return; 12395 if (argvars[2].v_type != VAR_UNKNOWN) 12396 { 12397 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr); 12398 if (typeerr) 12399 return; 12400 } 12401 } 12402 else 12403 maxcount = 25; 12404 12405 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE); 12406 12407 for (i = 0; i < ga.ga_len; ++i) 12408 { 12409 str = ((char_u **)ga.ga_data)[i]; 12410 12411 li = listitem_alloc(); 12412 if (li == NULL) 12413 vim_free(str); 12414 else 12415 { 12416 li->li_tv.v_type = VAR_STRING; 12417 li->li_tv.v_lock = 0; 12418 li->li_tv.vval.v_string = str; 12419 list_append(rettv->vval.v_list, li); 12420 } 12421 } 12422 ga_clear(&ga); 12423 } 12424 #endif 12425 } 12426 12427 static void 12428 f_split(typval_T *argvars, typval_T *rettv) 12429 { 12430 char_u *str; 12431 char_u *end; 12432 char_u *pat = NULL; 12433 regmatch_T regmatch; 12434 char_u patbuf[NUMBUFLEN]; 12435 char_u *save_cpo; 12436 int match; 12437 colnr_T col = 0; 12438 int keepempty = FALSE; 12439 int typeerr = FALSE; 12440 12441 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ 12442 save_cpo = p_cpo; 12443 p_cpo = (char_u *)""; 12444 12445 str = tv_get_string(&argvars[0]); 12446 if (argvars[1].v_type != VAR_UNKNOWN) 12447 { 12448 pat = tv_get_string_buf_chk(&argvars[1], patbuf); 12449 if (pat == NULL) 12450 typeerr = TRUE; 12451 if (argvars[2].v_type != VAR_UNKNOWN) 12452 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr); 12453 } 12454 if (pat == NULL || *pat == NUL) 12455 pat = (char_u *)"[\\x01- ]\\+"; 12456 12457 if (rettv_list_alloc(rettv) == FAIL) 12458 return; 12459 if (typeerr) 12460 return; 12461 12462 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); 12463 if (regmatch.regprog != NULL) 12464 { 12465 regmatch.rm_ic = FALSE; 12466 while (*str != NUL || keepempty) 12467 { 12468 if (*str == NUL) 12469 match = FALSE; /* empty item at the end */ 12470 else 12471 match = vim_regexec_nl(®match, str, col); 12472 if (match) 12473 end = regmatch.startp[0]; 12474 else 12475 end = str + STRLEN(str); 12476 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0 12477 && *str != NUL && match && end < regmatch.endp[0])) 12478 { 12479 if (list_append_string(rettv->vval.v_list, str, 12480 (int)(end - str)) == FAIL) 12481 break; 12482 } 12483 if (!match) 12484 break; 12485 // Advance to just after the match. 12486 if (regmatch.endp[0] > str) 12487 col = 0; 12488 else 12489 // Don't get stuck at the same match. 12490 col = (*mb_ptr2len)(regmatch.endp[0]); 12491 str = regmatch.endp[0]; 12492 } 12493 12494 vim_regfree(regmatch.regprog); 12495 } 12496 12497 p_cpo = save_cpo; 12498 } 12499 12500 #ifdef FEAT_FLOAT 12501 /* 12502 * "sqrt()" function 12503 */ 12504 static void 12505 f_sqrt(typval_T *argvars, typval_T *rettv) 12506 { 12507 float_T f = 0.0; 12508 12509 rettv->v_type = VAR_FLOAT; 12510 if (get_float_arg(argvars, &f) == OK) 12511 rettv->vval.v_float = sqrt(f); 12512 else 12513 rettv->vval.v_float = 0.0; 12514 } 12515 12516 /* 12517 * "str2float()" function 12518 */ 12519 static void 12520 f_str2float(typval_T *argvars, typval_T *rettv) 12521 { 12522 char_u *p = skipwhite(tv_get_string(&argvars[0])); 12523 int isneg = (*p == '-'); 12524 12525 if (*p == '+' || *p == '-') 12526 p = skipwhite(p + 1); 12527 (void)string2float(p, &rettv->vval.v_float); 12528 if (isneg) 12529 rettv->vval.v_float *= -1; 12530 rettv->v_type = VAR_FLOAT; 12531 } 12532 #endif 12533 12534 /* 12535 * "str2nr()" function 12536 */ 12537 static void 12538 f_str2nr(typval_T *argvars, typval_T *rettv) 12539 { 12540 int base = 10; 12541 char_u *p; 12542 varnumber_T n; 12543 int what; 12544 int isneg; 12545 12546 if (argvars[1].v_type != VAR_UNKNOWN) 12547 { 12548 base = (int)tv_get_number(&argvars[1]); 12549 if (base != 2 && base != 8 && base != 10 && base != 16) 12550 { 12551 emsg(_(e_invarg)); 12552 return; 12553 } 12554 } 12555 12556 p = skipwhite(tv_get_string(&argvars[0])); 12557 isneg = (*p == '-'); 12558 if (*p == '+' || *p == '-') 12559 p = skipwhite(p + 1); 12560 switch (base) 12561 { 12562 case 2: what = STR2NR_BIN + STR2NR_FORCE; break; 12563 case 8: what = STR2NR_OCT + STR2NR_FORCE; break; 12564 case 16: what = STR2NR_HEX + STR2NR_FORCE; break; 12565 default: what = 0; 12566 } 12567 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0); 12568 if (isneg) 12569 rettv->vval.v_number = -n; 12570 else 12571 rettv->vval.v_number = n; 12572 12573 } 12574 12575 #ifdef HAVE_STRFTIME 12576 /* 12577 * "strftime({format}[, {time}])" function 12578 */ 12579 static void 12580 f_strftime(typval_T *argvars, typval_T *rettv) 12581 { 12582 char_u result_buf[256]; 12583 struct tm *curtime; 12584 time_t seconds; 12585 char_u *p; 12586 12587 rettv->v_type = VAR_STRING; 12588 12589 p = tv_get_string(&argvars[0]); 12590 if (argvars[1].v_type == VAR_UNKNOWN) 12591 seconds = time(NULL); 12592 else 12593 seconds = (time_t)tv_get_number(&argvars[1]); 12594 curtime = localtime(&seconds); 12595 /* MSVC returns NULL for an invalid value of seconds. */ 12596 if (curtime == NULL) 12597 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)")); 12598 else 12599 { 12600 vimconv_T conv; 12601 char_u *enc; 12602 12603 conv.vc_type = CONV_NONE; 12604 enc = enc_locale(); 12605 convert_setup(&conv, p_enc, enc); 12606 if (conv.vc_type != CONV_NONE) 12607 p = string_convert(&conv, p, NULL); 12608 if (p != NULL) 12609 (void)strftime((char *)result_buf, sizeof(result_buf), 12610 (char *)p, curtime); 12611 else 12612 result_buf[0] = NUL; 12613 12614 if (conv.vc_type != CONV_NONE) 12615 vim_free(p); 12616 convert_setup(&conv, enc, p_enc); 12617 if (conv.vc_type != CONV_NONE) 12618 rettv->vval.v_string = string_convert(&conv, result_buf, NULL); 12619 else 12620 rettv->vval.v_string = vim_strsave(result_buf); 12621 12622 /* Release conversion descriptors */ 12623 convert_setup(&conv, NULL, NULL); 12624 vim_free(enc); 12625 } 12626 } 12627 #endif 12628 12629 /* 12630 * "strgetchar()" function 12631 */ 12632 static void 12633 f_strgetchar(typval_T *argvars, typval_T *rettv) 12634 { 12635 char_u *str; 12636 int len; 12637 int error = FALSE; 12638 int charidx; 12639 int byteidx = 0; 12640 12641 rettv->vval.v_number = -1; 12642 str = tv_get_string_chk(&argvars[0]); 12643 if (str == NULL) 12644 return; 12645 len = (int)STRLEN(str); 12646 charidx = (int)tv_get_number_chk(&argvars[1], &error); 12647 if (error) 12648 return; 12649 12650 while (charidx >= 0 && byteidx < len) 12651 { 12652 if (charidx == 0) 12653 { 12654 rettv->vval.v_number = mb_ptr2char(str + byteidx); 12655 break; 12656 } 12657 --charidx; 12658 byteidx += MB_CPTR2LEN(str + byteidx); 12659 } 12660 } 12661 12662 /* 12663 * "stridx()" function 12664 */ 12665 static void 12666 f_stridx(typval_T *argvars, typval_T *rettv) 12667 { 12668 char_u buf[NUMBUFLEN]; 12669 char_u *needle; 12670 char_u *haystack; 12671 char_u *save_haystack; 12672 char_u *pos; 12673 int start_idx; 12674 12675 needle = tv_get_string_chk(&argvars[1]); 12676 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf); 12677 rettv->vval.v_number = -1; 12678 if (needle == NULL || haystack == NULL) 12679 return; /* type error; errmsg already given */ 12680 12681 if (argvars[2].v_type != VAR_UNKNOWN) 12682 { 12683 int error = FALSE; 12684 12685 start_idx = (int)tv_get_number_chk(&argvars[2], &error); 12686 if (error || start_idx >= (int)STRLEN(haystack)) 12687 return; 12688 if (start_idx >= 0) 12689 haystack += start_idx; 12690 } 12691 12692 pos = (char_u *)strstr((char *)haystack, (char *)needle); 12693 if (pos != NULL) 12694 rettv->vval.v_number = (varnumber_T)(pos - save_haystack); 12695 } 12696 12697 /* 12698 * "string()" function 12699 */ 12700 void 12701 f_string(typval_T *argvars, typval_T *rettv) 12702 { 12703 char_u *tofree; 12704 char_u numbuf[NUMBUFLEN]; 12705 12706 rettv->v_type = VAR_STRING; 12707 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf, 12708 get_copyID()); 12709 /* Make a copy if we have a value but it's not in allocated memory. */ 12710 if (rettv->vval.v_string != NULL && tofree == NULL) 12711 rettv->vval.v_string = vim_strsave(rettv->vval.v_string); 12712 } 12713 12714 /* 12715 * "strlen()" function 12716 */ 12717 static void 12718 f_strlen(typval_T *argvars, typval_T *rettv) 12719 { 12720 rettv->vval.v_number = (varnumber_T)(STRLEN( 12721 tv_get_string(&argvars[0]))); 12722 } 12723 12724 /* 12725 * "strchars()" function 12726 */ 12727 static void 12728 f_strchars(typval_T *argvars, typval_T *rettv) 12729 { 12730 char_u *s = tv_get_string(&argvars[0]); 12731 int skipcc = 0; 12732 varnumber_T len = 0; 12733 int (*func_mb_ptr2char_adv)(char_u **pp); 12734 12735 if (argvars[1].v_type != VAR_UNKNOWN) 12736 skipcc = (int)tv_get_number_chk(&argvars[1], NULL); 12737 if (skipcc < 0 || skipcc > 1) 12738 emsg(_(e_invarg)); 12739 else 12740 { 12741 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv; 12742 while (*s != NUL) 12743 { 12744 func_mb_ptr2char_adv(&s); 12745 ++len; 12746 } 12747 rettv->vval.v_number = len; 12748 } 12749 } 12750 12751 /* 12752 * "strdisplaywidth()" function 12753 */ 12754 static void 12755 f_strdisplaywidth(typval_T *argvars, typval_T *rettv) 12756 { 12757 char_u *s = tv_get_string(&argvars[0]); 12758 int col = 0; 12759 12760 if (argvars[1].v_type != VAR_UNKNOWN) 12761 col = (int)tv_get_number(&argvars[1]); 12762 12763 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col); 12764 } 12765 12766 /* 12767 * "strwidth()" function 12768 */ 12769 static void 12770 f_strwidth(typval_T *argvars, typval_T *rettv) 12771 { 12772 char_u *s = tv_get_string(&argvars[0]); 12773 12774 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1)); 12775 } 12776 12777 /* 12778 * "strcharpart()" function 12779 */ 12780 static void 12781 f_strcharpart(typval_T *argvars, typval_T *rettv) 12782 { 12783 char_u *p; 12784 int nchar; 12785 int nbyte = 0; 12786 int charlen; 12787 int len = 0; 12788 int slen; 12789 int error = FALSE; 12790 12791 p = tv_get_string(&argvars[0]); 12792 slen = (int)STRLEN(p); 12793 12794 nchar = (int)tv_get_number_chk(&argvars[1], &error); 12795 if (!error) 12796 { 12797 if (nchar > 0) 12798 while (nchar > 0 && nbyte < slen) 12799 { 12800 nbyte += MB_CPTR2LEN(p + nbyte); 12801 --nchar; 12802 } 12803 else 12804 nbyte = nchar; 12805 if (argvars[2].v_type != VAR_UNKNOWN) 12806 { 12807 charlen = (int)tv_get_number(&argvars[2]); 12808 while (charlen > 0 && nbyte + len < slen) 12809 { 12810 int off = nbyte + len; 12811 12812 if (off < 0) 12813 len += 1; 12814 else 12815 len += MB_CPTR2LEN(p + off); 12816 --charlen; 12817 } 12818 } 12819 else 12820 len = slen - nbyte; /* default: all bytes that are available. */ 12821 } 12822 12823 /* 12824 * Only return the overlap between the specified part and the actual 12825 * string. 12826 */ 12827 if (nbyte < 0) 12828 { 12829 len += nbyte; 12830 nbyte = 0; 12831 } 12832 else if (nbyte > slen) 12833 nbyte = slen; 12834 if (len < 0) 12835 len = 0; 12836 else if (nbyte + len > slen) 12837 len = slen - nbyte; 12838 12839 rettv->v_type = VAR_STRING; 12840 rettv->vval.v_string = vim_strnsave(p + nbyte, len); 12841 } 12842 12843 /* 12844 * "strpart()" function 12845 */ 12846 static void 12847 f_strpart(typval_T *argvars, typval_T *rettv) 12848 { 12849 char_u *p; 12850 int n; 12851 int len; 12852 int slen; 12853 int error = FALSE; 12854 12855 p = tv_get_string(&argvars[0]); 12856 slen = (int)STRLEN(p); 12857 12858 n = (int)tv_get_number_chk(&argvars[1], &error); 12859 if (error) 12860 len = 0; 12861 else if (argvars[2].v_type != VAR_UNKNOWN) 12862 len = (int)tv_get_number(&argvars[2]); 12863 else 12864 len = slen - n; /* default len: all bytes that are available. */ 12865 12866 /* 12867 * Only return the overlap between the specified part and the actual 12868 * string. 12869 */ 12870 if (n < 0) 12871 { 12872 len += n; 12873 n = 0; 12874 } 12875 else if (n > slen) 12876 n = slen; 12877 if (len < 0) 12878 len = 0; 12879 else if (n + len > slen) 12880 len = slen - n; 12881 12882 rettv->v_type = VAR_STRING; 12883 rettv->vval.v_string = vim_strnsave(p + n, len); 12884 } 12885 12886 /* 12887 * "strridx()" function 12888 */ 12889 static void 12890 f_strridx(typval_T *argvars, typval_T *rettv) 12891 { 12892 char_u buf[NUMBUFLEN]; 12893 char_u *needle; 12894 char_u *haystack; 12895 char_u *rest; 12896 char_u *lastmatch = NULL; 12897 int haystack_len, end_idx; 12898 12899 needle = tv_get_string_chk(&argvars[1]); 12900 haystack = tv_get_string_buf_chk(&argvars[0], buf); 12901 12902 rettv->vval.v_number = -1; 12903 if (needle == NULL || haystack == NULL) 12904 return; /* type error; errmsg already given */ 12905 12906 haystack_len = (int)STRLEN(haystack); 12907 if (argvars[2].v_type != VAR_UNKNOWN) 12908 { 12909 /* Third argument: upper limit for index */ 12910 end_idx = (int)tv_get_number_chk(&argvars[2], NULL); 12911 if (end_idx < 0) 12912 return; /* can never find a match */ 12913 } 12914 else 12915 end_idx = haystack_len; 12916 12917 if (*needle == NUL) 12918 { 12919 /* Empty string matches past the end. */ 12920 lastmatch = haystack + end_idx; 12921 } 12922 else 12923 { 12924 for (rest = haystack; *rest != '\0'; ++rest) 12925 { 12926 rest = (char_u *)strstr((char *)rest, (char *)needle); 12927 if (rest == NULL || rest > haystack + end_idx) 12928 break; 12929 lastmatch = rest; 12930 } 12931 } 12932 12933 if (lastmatch == NULL) 12934 rettv->vval.v_number = -1; 12935 else 12936 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack); 12937 } 12938 12939 /* 12940 * "strtrans()" function 12941 */ 12942 static void 12943 f_strtrans(typval_T *argvars, typval_T *rettv) 12944 { 12945 rettv->v_type = VAR_STRING; 12946 rettv->vval.v_string = transstr(tv_get_string(&argvars[0])); 12947 } 12948 12949 /* 12950 * "submatch()" function 12951 */ 12952 static void 12953 f_submatch(typval_T *argvars, typval_T *rettv) 12954 { 12955 int error = FALSE; 12956 int no; 12957 int retList = 0; 12958 12959 no = (int)tv_get_number_chk(&argvars[0], &error); 12960 if (error) 12961 return; 12962 if (no < 0 || no >= NSUBEXP) 12963 { 12964 semsg(_("E935: invalid submatch number: %d"), no); 12965 return; 12966 } 12967 if (argvars[1].v_type != VAR_UNKNOWN) 12968 retList = (int)tv_get_number_chk(&argvars[1], &error); 12969 if (error) 12970 return; 12971 12972 if (retList == 0) 12973 { 12974 rettv->v_type = VAR_STRING; 12975 rettv->vval.v_string = reg_submatch(no); 12976 } 12977 else 12978 { 12979 rettv->v_type = VAR_LIST; 12980 rettv->vval.v_list = reg_submatch_list(no); 12981 } 12982 } 12983 12984 /* 12985 * "substitute()" function 12986 */ 12987 static void 12988 f_substitute(typval_T *argvars, typval_T *rettv) 12989 { 12990 char_u patbuf[NUMBUFLEN]; 12991 char_u subbuf[NUMBUFLEN]; 12992 char_u flagsbuf[NUMBUFLEN]; 12993 12994 char_u *str = tv_get_string_chk(&argvars[0]); 12995 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf); 12996 char_u *sub = NULL; 12997 typval_T *expr = NULL; 12998 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf); 12999 13000 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL) 13001 expr = &argvars[2]; 13002 else 13003 sub = tv_get_string_buf_chk(&argvars[2], subbuf); 13004 13005 rettv->v_type = VAR_STRING; 13006 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL) 13007 || flg == NULL) 13008 rettv->vval.v_string = NULL; 13009 else 13010 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg); 13011 } 13012 13013 /* 13014 * "swapinfo(swap_filename)" function 13015 */ 13016 static void 13017 f_swapinfo(typval_T *argvars, typval_T *rettv) 13018 { 13019 if (rettv_dict_alloc(rettv) == OK) 13020 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict); 13021 } 13022 13023 /* 13024 * "swapname(expr)" function 13025 */ 13026 static void 13027 f_swapname(typval_T *argvars, typval_T *rettv) 13028 { 13029 buf_T *buf; 13030 13031 rettv->v_type = VAR_STRING; 13032 buf = tv_get_buf(&argvars[0], FALSE); 13033 if (buf == NULL || buf->b_ml.ml_mfp == NULL 13034 || buf->b_ml.ml_mfp->mf_fname == NULL) 13035 rettv->vval.v_string = NULL; 13036 else 13037 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname); 13038 } 13039 13040 /* 13041 * "synID(lnum, col, trans)" function 13042 */ 13043 static void 13044 f_synID(typval_T *argvars UNUSED, typval_T *rettv) 13045 { 13046 int id = 0; 13047 #ifdef FEAT_SYN_HL 13048 linenr_T lnum; 13049 colnr_T col; 13050 int trans; 13051 int transerr = FALSE; 13052 13053 lnum = tv_get_lnum(argvars); /* -1 on type error */ 13054 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */ 13055 trans = (int)tv_get_number_chk(&argvars[2], &transerr); 13056 13057 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count 13058 && col >= 0 && col < (long)STRLEN(ml_get(lnum))) 13059 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE); 13060 #endif 13061 13062 rettv->vval.v_number = id; 13063 } 13064 13065 /* 13066 * "synIDattr(id, what [, mode])" function 13067 */ 13068 static void 13069 f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv) 13070 { 13071 char_u *p = NULL; 13072 #ifdef FEAT_SYN_HL 13073 int id; 13074 char_u *what; 13075 char_u *mode; 13076 char_u modebuf[NUMBUFLEN]; 13077 int modec; 13078 13079 id = (int)tv_get_number(&argvars[0]); 13080 what = tv_get_string(&argvars[1]); 13081 if (argvars[2].v_type != VAR_UNKNOWN) 13082 { 13083 mode = tv_get_string_buf(&argvars[2], modebuf); 13084 modec = TOLOWER_ASC(mode[0]); 13085 if (modec != 't' && modec != 'c' && modec != 'g') 13086 modec = 0; /* replace invalid with current */ 13087 } 13088 else 13089 { 13090 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 13091 if (USE_24BIT) 13092 modec = 'g'; 13093 else 13094 #endif 13095 if (t_colors > 1) 13096 modec = 'c'; 13097 else 13098 modec = 't'; 13099 } 13100 13101 switch (TOLOWER_ASC(what[0])) 13102 { 13103 case 'b': 13104 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */ 13105 p = highlight_color(id, what, modec); 13106 else /* bold */ 13107 p = highlight_has_attr(id, HL_BOLD, modec); 13108 break; 13109 13110 case 'f': /* fg[#] or font */ 13111 p = highlight_color(id, what, modec); 13112 break; 13113 13114 case 'i': 13115 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */ 13116 p = highlight_has_attr(id, HL_INVERSE, modec); 13117 else /* italic */ 13118 p = highlight_has_attr(id, HL_ITALIC, modec); 13119 break; 13120 13121 case 'n': /* name */ 13122 p = get_highlight_name_ext(NULL, id - 1, FALSE); 13123 break; 13124 13125 case 'r': /* reverse */ 13126 p = highlight_has_attr(id, HL_INVERSE, modec); 13127 break; 13128 13129 case 's': 13130 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */ 13131 p = highlight_color(id, what, modec); 13132 /* strikeout */ 13133 else if (TOLOWER_ASC(what[1]) == 't' && 13134 TOLOWER_ASC(what[2]) == 'r') 13135 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec); 13136 else /* standout */ 13137 p = highlight_has_attr(id, HL_STANDOUT, modec); 13138 break; 13139 13140 case 'u': 13141 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c') 13142 /* underline */ 13143 p = highlight_has_attr(id, HL_UNDERLINE, modec); 13144 else 13145 /* undercurl */ 13146 p = highlight_has_attr(id, HL_UNDERCURL, modec); 13147 break; 13148 } 13149 13150 if (p != NULL) 13151 p = vim_strsave(p); 13152 #endif 13153 rettv->v_type = VAR_STRING; 13154 rettv->vval.v_string = p; 13155 } 13156 13157 /* 13158 * "synIDtrans(id)" function 13159 */ 13160 static void 13161 f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv) 13162 { 13163 int id; 13164 13165 #ifdef FEAT_SYN_HL 13166 id = (int)tv_get_number(&argvars[0]); 13167 13168 if (id > 0) 13169 id = syn_get_final_id(id); 13170 else 13171 #endif 13172 id = 0; 13173 13174 rettv->vval.v_number = id; 13175 } 13176 13177 /* 13178 * "synconcealed(lnum, col)" function 13179 */ 13180 static void 13181 f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv) 13182 { 13183 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) 13184 linenr_T lnum; 13185 colnr_T col; 13186 int syntax_flags = 0; 13187 int cchar; 13188 int matchid = 0; 13189 char_u str[NUMBUFLEN]; 13190 #endif 13191 13192 rettv_list_set(rettv, NULL); 13193 13194 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) 13195 lnum = tv_get_lnum(argvars); /* -1 on type error */ 13196 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */ 13197 13198 vim_memset(str, NUL, sizeof(str)); 13199 13200 if (rettv_list_alloc(rettv) != FAIL) 13201 { 13202 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count 13203 && col >= 0 && col <= (long)STRLEN(ml_get(lnum)) 13204 && curwin->w_p_cole > 0) 13205 { 13206 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE); 13207 syntax_flags = get_syntax_info(&matchid); 13208 13209 /* get the conceal character */ 13210 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3) 13211 { 13212 cchar = syn_get_sub_char(); 13213 if (cchar == NUL && curwin->w_p_cole == 1) 13214 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal; 13215 if (cchar != NUL) 13216 { 13217 if (has_mbyte) 13218 (*mb_char2bytes)(cchar, str); 13219 else 13220 str[0] = cchar; 13221 } 13222 } 13223 } 13224 13225 list_append_number(rettv->vval.v_list, 13226 (syntax_flags & HL_CONCEAL) != 0); 13227 /* -1 to auto-determine strlen */ 13228 list_append_string(rettv->vval.v_list, str, -1); 13229 list_append_number(rettv->vval.v_list, matchid); 13230 } 13231 #endif 13232 } 13233 13234 /* 13235 * "synstack(lnum, col)" function 13236 */ 13237 static void 13238 f_synstack(typval_T *argvars UNUSED, typval_T *rettv) 13239 { 13240 #ifdef FEAT_SYN_HL 13241 linenr_T lnum; 13242 colnr_T col; 13243 int i; 13244 int id; 13245 #endif 13246 13247 rettv_list_set(rettv, NULL); 13248 13249 #ifdef FEAT_SYN_HL 13250 lnum = tv_get_lnum(argvars); /* -1 on type error */ 13251 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */ 13252 13253 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count 13254 && col >= 0 && col <= (long)STRLEN(ml_get(lnum)) 13255 && rettv_list_alloc(rettv) != FAIL) 13256 { 13257 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE); 13258 for (i = 0; ; ++i) 13259 { 13260 id = syn_get_stack_item(i); 13261 if (id < 0) 13262 break; 13263 if (list_append_number(rettv->vval.v_list, id) == FAIL) 13264 break; 13265 } 13266 } 13267 #endif 13268 } 13269 13270 static void 13271 get_cmd_output_as_rettv( 13272 typval_T *argvars, 13273 typval_T *rettv, 13274 int retlist) 13275 { 13276 char_u *res = NULL; 13277 char_u *p; 13278 char_u *infile = NULL; 13279 int err = FALSE; 13280 FILE *fd; 13281 list_T *list = NULL; 13282 int flags = SHELL_SILENT; 13283 13284 rettv->v_type = VAR_STRING; 13285 rettv->vval.v_string = NULL; 13286 if (check_restricted() || check_secure()) 13287 goto errret; 13288 13289 if (argvars[1].v_type != VAR_UNKNOWN) 13290 { 13291 /* 13292 * Write the text to a temp file, to be used for input of the shell 13293 * command. 13294 */ 13295 if ((infile = vim_tempname('i', TRUE)) == NULL) 13296 { 13297 emsg(_(e_notmp)); 13298 goto errret; 13299 } 13300 13301 fd = mch_fopen((char *)infile, WRITEBIN); 13302 if (fd == NULL) 13303 { 13304 semsg(_(e_notopen), infile); 13305 goto errret; 13306 } 13307 if (argvars[1].v_type == VAR_NUMBER) 13308 { 13309 linenr_T lnum; 13310 buf_T *buf; 13311 13312 buf = buflist_findnr(argvars[1].vval.v_number); 13313 if (buf == NULL) 13314 { 13315 semsg(_(e_nobufnr), argvars[1].vval.v_number); 13316 fclose(fd); 13317 goto errret; 13318 } 13319 13320 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) 13321 { 13322 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p) 13323 if (putc(*p == '\n' ? NUL : *p, fd) == EOF) 13324 { 13325 err = TRUE; 13326 break; 13327 } 13328 if (putc(NL, fd) == EOF) 13329 { 13330 err = TRUE; 13331 break; 13332 } 13333 } 13334 } 13335 else if (argvars[1].v_type == VAR_LIST) 13336 { 13337 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL) 13338 err = TRUE; 13339 } 13340 else 13341 { 13342 size_t len; 13343 char_u buf[NUMBUFLEN]; 13344 13345 p = tv_get_string_buf_chk(&argvars[1], buf); 13346 if (p == NULL) 13347 { 13348 fclose(fd); 13349 goto errret; /* type error; errmsg already given */ 13350 } 13351 len = STRLEN(p); 13352 if (len > 0 && fwrite(p, len, 1, fd) != 1) 13353 err = TRUE; 13354 } 13355 if (fclose(fd) != 0) 13356 err = TRUE; 13357 if (err) 13358 { 13359 emsg(_("E677: Error writing temp file")); 13360 goto errret; 13361 } 13362 } 13363 13364 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell 13365 * echoes typeahead, that messes up the display. */ 13366 if (!msg_silent) 13367 flags += SHELL_COOKED; 13368 13369 if (retlist) 13370 { 13371 int len; 13372 listitem_T *li; 13373 char_u *s = NULL; 13374 char_u *start; 13375 char_u *end; 13376 int i; 13377 13378 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len); 13379 if (res == NULL) 13380 goto errret; 13381 13382 list = list_alloc(); 13383 if (list == NULL) 13384 goto errret; 13385 13386 for (i = 0; i < len; ++i) 13387 { 13388 start = res + i; 13389 while (i < len && res[i] != NL) 13390 ++i; 13391 end = res + i; 13392 13393 s = alloc((unsigned)(end - start + 1)); 13394 if (s == NULL) 13395 goto errret; 13396 13397 for (p = s; start < end; ++p, ++start) 13398 *p = *start == NUL ? NL : *start; 13399 *p = NUL; 13400 13401 li = listitem_alloc(); 13402 if (li == NULL) 13403 { 13404 vim_free(s); 13405 goto errret; 13406 } 13407 li->li_tv.v_type = VAR_STRING; 13408 li->li_tv.v_lock = 0; 13409 li->li_tv.vval.v_string = s; 13410 list_append(list, li); 13411 } 13412 13413 rettv_list_set(rettv, list); 13414 list = NULL; 13415 } 13416 else 13417 { 13418 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL); 13419 #ifdef USE_CR 13420 /* translate <CR> into <NL> */ 13421 if (res != NULL) 13422 { 13423 char_u *s; 13424 13425 for (s = res; *s; ++s) 13426 { 13427 if (*s == CAR) 13428 *s = NL; 13429 } 13430 } 13431 #else 13432 # ifdef USE_CRNL 13433 /* translate <CR><NL> into <NL> */ 13434 if (res != NULL) 13435 { 13436 char_u *s, *d; 13437 13438 d = res; 13439 for (s = res; *s; ++s) 13440 { 13441 if (s[0] == CAR && s[1] == NL) 13442 ++s; 13443 *d++ = *s; 13444 } 13445 *d = NUL; 13446 } 13447 # endif 13448 #endif 13449 rettv->vval.v_string = res; 13450 res = NULL; 13451 } 13452 13453 errret: 13454 if (infile != NULL) 13455 { 13456 mch_remove(infile); 13457 vim_free(infile); 13458 } 13459 if (res != NULL) 13460 vim_free(res); 13461 if (list != NULL) 13462 list_free(list); 13463 } 13464 13465 /* 13466 * "system()" function 13467 */ 13468 static void 13469 f_system(typval_T *argvars, typval_T *rettv) 13470 { 13471 get_cmd_output_as_rettv(argvars, rettv, FALSE); 13472 } 13473 13474 /* 13475 * "systemlist()" function 13476 */ 13477 static void 13478 f_systemlist(typval_T *argvars, typval_T *rettv) 13479 { 13480 get_cmd_output_as_rettv(argvars, rettv, TRUE); 13481 } 13482 13483 /* 13484 * "tabpagebuflist()" function 13485 */ 13486 static void 13487 f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 13488 { 13489 tabpage_T *tp; 13490 win_T *wp = NULL; 13491 13492 if (argvars[0].v_type == VAR_UNKNOWN) 13493 wp = firstwin; 13494 else 13495 { 13496 tp = find_tabpage((int)tv_get_number(&argvars[0])); 13497 if (tp != NULL) 13498 wp = (tp == curtab) ? firstwin : tp->tp_firstwin; 13499 } 13500 if (wp != NULL && rettv_list_alloc(rettv) != FAIL) 13501 { 13502 for (; wp != NULL; wp = wp->w_next) 13503 if (list_append_number(rettv->vval.v_list, 13504 wp->w_buffer->b_fnum) == FAIL) 13505 break; 13506 } 13507 } 13508 13509 /* 13510 * "tabpagenr()" function 13511 */ 13512 static void 13513 f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv) 13514 { 13515 int nr = 1; 13516 char_u *arg; 13517 13518 if (argvars[0].v_type != VAR_UNKNOWN) 13519 { 13520 arg = tv_get_string_chk(&argvars[0]); 13521 nr = 0; 13522 if (arg != NULL) 13523 { 13524 if (STRCMP(arg, "$") == 0) 13525 nr = tabpage_index(NULL) - 1; 13526 else 13527 semsg(_(e_invexpr2), arg); 13528 } 13529 } 13530 else 13531 nr = tabpage_index(curtab); 13532 rettv->vval.v_number = nr; 13533 } 13534 13535 13536 /* 13537 * Common code for tabpagewinnr() and winnr(). 13538 */ 13539 static int 13540 get_winnr(tabpage_T *tp, typval_T *argvar) 13541 { 13542 win_T *twin; 13543 int nr = 1; 13544 win_T *wp; 13545 char_u *arg; 13546 13547 twin = (tp == curtab) ? curwin : tp->tp_curwin; 13548 if (argvar->v_type != VAR_UNKNOWN) 13549 { 13550 arg = tv_get_string_chk(argvar); 13551 if (arg == NULL) 13552 nr = 0; /* type error; errmsg already given */ 13553 else if (STRCMP(arg, "$") == 0) 13554 twin = (tp == curtab) ? lastwin : tp->tp_lastwin; 13555 else if (STRCMP(arg, "#") == 0) 13556 { 13557 twin = (tp == curtab) ? prevwin : tp->tp_prevwin; 13558 if (twin == NULL) 13559 nr = 0; 13560 } 13561 else 13562 { 13563 semsg(_(e_invexpr2), arg); 13564 nr = 0; 13565 } 13566 } 13567 13568 if (nr > 0) 13569 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin; 13570 wp != twin; wp = wp->w_next) 13571 { 13572 if (wp == NULL) 13573 { 13574 /* didn't find it in this tabpage */ 13575 nr = 0; 13576 break; 13577 } 13578 ++nr; 13579 } 13580 return nr; 13581 } 13582 13583 /* 13584 * "tabpagewinnr()" function 13585 */ 13586 static void 13587 f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv) 13588 { 13589 int nr = 1; 13590 tabpage_T *tp; 13591 13592 tp = find_tabpage((int)tv_get_number(&argvars[0])); 13593 if (tp == NULL) 13594 nr = 0; 13595 else 13596 nr = get_winnr(tp, &argvars[1]); 13597 rettv->vval.v_number = nr; 13598 } 13599 13600 /* 13601 * "tagfiles()" function 13602 */ 13603 static void 13604 f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv) 13605 { 13606 char_u *fname; 13607 tagname_T tn; 13608 int first; 13609 13610 if (rettv_list_alloc(rettv) == FAIL) 13611 return; 13612 fname = alloc(MAXPATHL); 13613 if (fname == NULL) 13614 return; 13615 13616 for (first = TRUE; ; first = FALSE) 13617 if (get_tagfname(&tn, first, fname) == FAIL 13618 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL) 13619 break; 13620 tagname_free(&tn); 13621 vim_free(fname); 13622 } 13623 13624 /* 13625 * "taglist()" function 13626 */ 13627 static void 13628 f_taglist(typval_T *argvars, typval_T *rettv) 13629 { 13630 char_u *fname = NULL; 13631 char_u *tag_pattern; 13632 13633 tag_pattern = tv_get_string(&argvars[0]); 13634 13635 rettv->vval.v_number = FALSE; 13636 if (*tag_pattern == NUL) 13637 return; 13638 13639 if (argvars[1].v_type != VAR_UNKNOWN) 13640 fname = tv_get_string(&argvars[1]); 13641 if (rettv_list_alloc(rettv) == OK) 13642 (void)get_tags(rettv->vval.v_list, tag_pattern, fname); 13643 } 13644 13645 /* 13646 * "tempname()" function 13647 */ 13648 static void 13649 f_tempname(typval_T *argvars UNUSED, typval_T *rettv) 13650 { 13651 static int x = 'A'; 13652 13653 rettv->v_type = VAR_STRING; 13654 rettv->vval.v_string = vim_tempname(x, FALSE); 13655 13656 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different 13657 * names. Skip 'I' and 'O', they are used for shell redirection. */ 13658 do 13659 { 13660 if (x == 'Z') 13661 x = '0'; 13662 else if (x == '9') 13663 x = 'A'; 13664 else 13665 { 13666 #ifdef EBCDIC 13667 if (x == 'I') 13668 x = 'J'; 13669 else if (x == 'R') 13670 x = 'S'; 13671 else 13672 #endif 13673 ++x; 13674 } 13675 } while (x == 'I' || x == 'O'); 13676 } 13677 13678 #ifdef FEAT_FLOAT 13679 /* 13680 * "tan()" function 13681 */ 13682 static void 13683 f_tan(typval_T *argvars, typval_T *rettv) 13684 { 13685 float_T f = 0.0; 13686 13687 rettv->v_type = VAR_FLOAT; 13688 if (get_float_arg(argvars, &f) == OK) 13689 rettv->vval.v_float = tan(f); 13690 else 13691 rettv->vval.v_float = 0.0; 13692 } 13693 13694 /* 13695 * "tanh()" function 13696 */ 13697 static void 13698 f_tanh(typval_T *argvars, typval_T *rettv) 13699 { 13700 float_T f = 0.0; 13701 13702 rettv->v_type = VAR_FLOAT; 13703 if (get_float_arg(argvars, &f) == OK) 13704 rettv->vval.v_float = tanh(f); 13705 else 13706 rettv->vval.v_float = 0.0; 13707 } 13708 #endif 13709 13710 /* 13711 * "test_alloc_fail(id, countdown, repeat)" function 13712 */ 13713 static void 13714 f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED) 13715 { 13716 if (argvars[0].v_type != VAR_NUMBER 13717 || argvars[0].vval.v_number <= 0 13718 || argvars[1].v_type != VAR_NUMBER 13719 || argvars[1].vval.v_number < 0 13720 || argvars[2].v_type != VAR_NUMBER) 13721 emsg(_(e_invarg)); 13722 else 13723 { 13724 alloc_fail_id = argvars[0].vval.v_number; 13725 if (alloc_fail_id >= aid_last) 13726 emsg(_(e_invarg)); 13727 alloc_fail_countdown = argvars[1].vval.v_number; 13728 alloc_fail_repeat = argvars[2].vval.v_number; 13729 did_outofmem_msg = FALSE; 13730 } 13731 } 13732 13733 /* 13734 * "test_autochdir()" 13735 */ 13736 static void 13737 f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 13738 { 13739 #if defined(FEAT_AUTOCHDIR) 13740 test_autochdir = TRUE; 13741 #endif 13742 } 13743 13744 /* 13745 * "test_feedinput()" 13746 */ 13747 static void 13748 f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED) 13749 { 13750 #ifdef USE_INPUT_BUF 13751 char_u *val = tv_get_string_chk(&argvars[0]); 13752 13753 if (val != NULL) 13754 { 13755 trash_input_buf(); 13756 add_to_input_buf_csi(val, (int)STRLEN(val)); 13757 } 13758 #endif 13759 } 13760 13761 /* 13762 * "test_option_not_set({name})" function 13763 */ 13764 static void 13765 f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED) 13766 { 13767 char_u *name = (char_u *)""; 13768 13769 if (argvars[0].v_type != VAR_STRING) 13770 emsg(_(e_invarg)); 13771 else 13772 { 13773 name = tv_get_string(&argvars[0]); 13774 if (reset_option_was_set(name) == FAIL) 13775 semsg(_(e_invarg2), name); 13776 } 13777 } 13778 13779 /* 13780 * "test_override({name}, {val})" function 13781 */ 13782 static void 13783 f_test_override(typval_T *argvars, typval_T *rettv UNUSED) 13784 { 13785 char_u *name = (char_u *)""; 13786 int val; 13787 static int save_starting = -1; 13788 13789 if (argvars[0].v_type != VAR_STRING 13790 || (argvars[1].v_type) != VAR_NUMBER) 13791 emsg(_(e_invarg)); 13792 else 13793 { 13794 name = tv_get_string(&argvars[0]); 13795 val = (int)tv_get_number(&argvars[1]); 13796 13797 if (STRCMP(name, (char_u *)"redraw") == 0) 13798 disable_redraw_for_testing = val; 13799 else if (STRCMP(name, (char_u *)"redraw_flag") == 0) 13800 ignore_redraw_flag_for_testing = val; 13801 else if (STRCMP(name, (char_u *)"char_avail") == 0) 13802 disable_char_avail_for_testing = val; 13803 else if (STRCMP(name, (char_u *)"starting") == 0) 13804 { 13805 if (val) 13806 { 13807 if (save_starting < 0) 13808 save_starting = starting; 13809 starting = 0; 13810 } 13811 else 13812 { 13813 starting = save_starting; 13814 save_starting = -1; 13815 } 13816 } 13817 else if (STRCMP(name, (char_u *)"nfa_fail") == 0) 13818 nfa_fail_for_testing = val; 13819 else if (STRCMP(name, (char_u *)"ALL") == 0) 13820 { 13821 disable_char_avail_for_testing = FALSE; 13822 disable_redraw_for_testing = FALSE; 13823 ignore_redraw_flag_for_testing = FALSE; 13824 nfa_fail_for_testing = FALSE; 13825 if (save_starting >= 0) 13826 { 13827 starting = save_starting; 13828 save_starting = -1; 13829 } 13830 } 13831 else 13832 semsg(_(e_invarg2), name); 13833 } 13834 } 13835 13836 /* 13837 * "test_garbagecollect_now()" function 13838 */ 13839 static void 13840 f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 13841 { 13842 /* This is dangerous, any Lists and Dicts used internally may be freed 13843 * while still in use. */ 13844 garbage_collect(TRUE); 13845 } 13846 13847 /* 13848 * "test_ignore_error()" function 13849 */ 13850 static void 13851 f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED) 13852 { 13853 ignore_error_for_testing(tv_get_string(&argvars[0])); 13854 } 13855 13856 static void 13857 f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv) 13858 { 13859 rettv->v_type = VAR_BLOB; 13860 rettv->vval.v_blob = NULL; 13861 } 13862 13863 #ifdef FEAT_JOB_CHANNEL 13864 static void 13865 f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv) 13866 { 13867 rettv->v_type = VAR_CHANNEL; 13868 rettv->vval.v_channel = NULL; 13869 } 13870 #endif 13871 13872 static void 13873 f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv) 13874 { 13875 rettv_dict_set(rettv, NULL); 13876 } 13877 13878 #ifdef FEAT_JOB_CHANNEL 13879 static void 13880 f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv) 13881 { 13882 rettv->v_type = VAR_JOB; 13883 rettv->vval.v_job = NULL; 13884 } 13885 #endif 13886 13887 static void 13888 f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv) 13889 { 13890 rettv_list_set(rettv, NULL); 13891 } 13892 13893 static void 13894 f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv) 13895 { 13896 rettv->v_type = VAR_PARTIAL; 13897 rettv->vval.v_partial = NULL; 13898 } 13899 13900 static void 13901 f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv) 13902 { 13903 rettv->v_type = VAR_STRING; 13904 rettv->vval.v_string = NULL; 13905 } 13906 13907 #ifdef FEAT_GUI 13908 static void 13909 f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED) 13910 { 13911 char_u *which; 13912 long value; 13913 int dragging; 13914 scrollbar_T *sb = NULL; 13915 13916 if (argvars[0].v_type != VAR_STRING 13917 || (argvars[1].v_type) != VAR_NUMBER 13918 || (argvars[2].v_type) != VAR_NUMBER) 13919 { 13920 emsg(_(e_invarg)); 13921 return; 13922 } 13923 which = tv_get_string(&argvars[0]); 13924 value = tv_get_number(&argvars[1]); 13925 dragging = tv_get_number(&argvars[2]); 13926 13927 if (STRCMP(which, "left") == 0) 13928 sb = &curwin->w_scrollbars[SBAR_LEFT]; 13929 else if (STRCMP(which, "right") == 0) 13930 sb = &curwin->w_scrollbars[SBAR_RIGHT]; 13931 else if (STRCMP(which, "hor") == 0) 13932 sb = &gui.bottom_sbar; 13933 if (sb == NULL) 13934 { 13935 semsg(_(e_invarg2), which); 13936 return; 13937 } 13938 gui_drag_scrollbar(sb, value, dragging); 13939 # ifndef USE_ON_FLY_SCROLL 13940 // need to loop through normal_cmd() to handle the scroll events 13941 exec_normal(FALSE, TRUE, FALSE); 13942 # endif 13943 } 13944 #endif 13945 13946 static void 13947 f_test_settime(typval_T *argvars, typval_T *rettv UNUSED) 13948 { 13949 time_for_testing = (time_t)tv_get_number(&argvars[0]); 13950 } 13951 13952 #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO) 13953 /* 13954 * Get a callback from "arg". It can be a Funcref or a function name. 13955 * When "arg" is zero return an empty string. 13956 * Return NULL for an invalid argument. 13957 */ 13958 char_u * 13959 get_callback(typval_T *arg, partial_T **pp) 13960 { 13961 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL) 13962 { 13963 *pp = arg->vval.v_partial; 13964 ++(*pp)->pt_refcount; 13965 return partial_name(*pp); 13966 } 13967 *pp = NULL; 13968 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING) 13969 { 13970 func_ref(arg->vval.v_string); 13971 return arg->vval.v_string; 13972 } 13973 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) 13974 return (char_u *)""; 13975 emsg(_("E921: Invalid callback argument")); 13976 return NULL; 13977 } 13978 13979 /* 13980 * Unref/free "callback" and "partial" returned by get_callback(). 13981 */ 13982 void 13983 free_callback(char_u *callback, partial_T *partial) 13984 { 13985 if (partial != NULL) 13986 partial_unref(partial); 13987 else if (callback != NULL) 13988 { 13989 func_unref(callback); 13990 vim_free(callback); 13991 } 13992 } 13993 #endif 13994 13995 #ifdef FEAT_TIMERS 13996 /* 13997 * "timer_info([timer])" function 13998 */ 13999 static void 14000 f_timer_info(typval_T *argvars, typval_T *rettv) 14001 { 14002 timer_T *timer = NULL; 14003 14004 if (rettv_list_alloc(rettv) != OK) 14005 return; 14006 if (argvars[0].v_type != VAR_UNKNOWN) 14007 { 14008 if (argvars[0].v_type != VAR_NUMBER) 14009 emsg(_(e_number_exp)); 14010 else 14011 { 14012 timer = find_timer((int)tv_get_number(&argvars[0])); 14013 if (timer != NULL) 14014 add_timer_info(rettv, timer); 14015 } 14016 } 14017 else 14018 add_timer_info_all(rettv); 14019 } 14020 14021 /* 14022 * "timer_pause(timer, paused)" function 14023 */ 14024 static void 14025 f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED) 14026 { 14027 timer_T *timer = NULL; 14028 int paused = (int)tv_get_number(&argvars[1]); 14029 14030 if (argvars[0].v_type != VAR_NUMBER) 14031 emsg(_(e_number_exp)); 14032 else 14033 { 14034 timer = find_timer((int)tv_get_number(&argvars[0])); 14035 if (timer != NULL) 14036 timer->tr_paused = paused; 14037 } 14038 } 14039 14040 /* 14041 * "timer_start(time, callback [, options])" function 14042 */ 14043 static void 14044 f_timer_start(typval_T *argvars, typval_T *rettv) 14045 { 14046 long msec = (long)tv_get_number(&argvars[0]); 14047 timer_T *timer; 14048 int repeat = 0; 14049 char_u *callback; 14050 dict_T *dict; 14051 partial_T *partial; 14052 14053 rettv->vval.v_number = -1; 14054 if (check_secure()) 14055 return; 14056 if (argvars[2].v_type != VAR_UNKNOWN) 14057 { 14058 if (argvars[2].v_type != VAR_DICT 14059 || (dict = argvars[2].vval.v_dict) == NULL) 14060 { 14061 semsg(_(e_invarg2), tv_get_string(&argvars[2])); 14062 return; 14063 } 14064 if (dict_find(dict, (char_u *)"repeat", -1) != NULL) 14065 repeat = dict_get_number(dict, (char_u *)"repeat"); 14066 } 14067 14068 callback = get_callback(&argvars[1], &partial); 14069 if (callback == NULL) 14070 return; 14071 14072 timer = create_timer(msec, repeat); 14073 if (timer == NULL) 14074 free_callback(callback, partial); 14075 else 14076 { 14077 if (partial == NULL) 14078 timer->tr_callback = vim_strsave(callback); 14079 else 14080 /* pointer into the partial */ 14081 timer->tr_callback = callback; 14082 timer->tr_partial = partial; 14083 rettv->vval.v_number = (varnumber_T)timer->tr_id; 14084 } 14085 } 14086 14087 /* 14088 * "timer_stop(timer)" function 14089 */ 14090 static void 14091 f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED) 14092 { 14093 timer_T *timer; 14094 14095 if (argvars[0].v_type != VAR_NUMBER) 14096 { 14097 emsg(_(e_number_exp)); 14098 return; 14099 } 14100 timer = find_timer((int)tv_get_number(&argvars[0])); 14101 if (timer != NULL) 14102 stop_timer(timer); 14103 } 14104 14105 /* 14106 * "timer_stopall()" function 14107 */ 14108 static void 14109 f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 14110 { 14111 stop_all_timers(); 14112 } 14113 #endif 14114 14115 /* 14116 * "tolower(string)" function 14117 */ 14118 static void 14119 f_tolower(typval_T *argvars, typval_T *rettv) 14120 { 14121 rettv->v_type = VAR_STRING; 14122 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0])); 14123 } 14124 14125 /* 14126 * "toupper(string)" function 14127 */ 14128 static void 14129 f_toupper(typval_T *argvars, typval_T *rettv) 14130 { 14131 rettv->v_type = VAR_STRING; 14132 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0])); 14133 } 14134 14135 /* 14136 * "tr(string, fromstr, tostr)" function 14137 */ 14138 static void 14139 f_tr(typval_T *argvars, typval_T *rettv) 14140 { 14141 char_u *in_str; 14142 char_u *fromstr; 14143 char_u *tostr; 14144 char_u *p; 14145 int inlen; 14146 int fromlen; 14147 int tolen; 14148 int idx; 14149 char_u *cpstr; 14150 int cplen; 14151 int first = TRUE; 14152 char_u buf[NUMBUFLEN]; 14153 char_u buf2[NUMBUFLEN]; 14154 garray_T ga; 14155 14156 in_str = tv_get_string(&argvars[0]); 14157 fromstr = tv_get_string_buf_chk(&argvars[1], buf); 14158 tostr = tv_get_string_buf_chk(&argvars[2], buf2); 14159 14160 /* Default return value: empty string. */ 14161 rettv->v_type = VAR_STRING; 14162 rettv->vval.v_string = NULL; 14163 if (fromstr == NULL || tostr == NULL) 14164 return; /* type error; errmsg already given */ 14165 ga_init2(&ga, (int)sizeof(char), 80); 14166 14167 if (!has_mbyte) 14168 /* not multi-byte: fromstr and tostr must be the same length */ 14169 if (STRLEN(fromstr) != STRLEN(tostr)) 14170 { 14171 error: 14172 semsg(_(e_invarg2), fromstr); 14173 ga_clear(&ga); 14174 return; 14175 } 14176 14177 /* fromstr and tostr have to contain the same number of chars */ 14178 while (*in_str != NUL) 14179 { 14180 if (has_mbyte) 14181 { 14182 inlen = (*mb_ptr2len)(in_str); 14183 cpstr = in_str; 14184 cplen = inlen; 14185 idx = 0; 14186 for (p = fromstr; *p != NUL; p += fromlen) 14187 { 14188 fromlen = (*mb_ptr2len)(p); 14189 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0) 14190 { 14191 for (p = tostr; *p != NUL; p += tolen) 14192 { 14193 tolen = (*mb_ptr2len)(p); 14194 if (idx-- == 0) 14195 { 14196 cplen = tolen; 14197 cpstr = p; 14198 break; 14199 } 14200 } 14201 if (*p == NUL) /* tostr is shorter than fromstr */ 14202 goto error; 14203 break; 14204 } 14205 ++idx; 14206 } 14207 14208 if (first && cpstr == in_str) 14209 { 14210 /* Check that fromstr and tostr have the same number of 14211 * (multi-byte) characters. Done only once when a character 14212 * of in_str doesn't appear in fromstr. */ 14213 first = FALSE; 14214 for (p = tostr; *p != NUL; p += tolen) 14215 { 14216 tolen = (*mb_ptr2len)(p); 14217 --idx; 14218 } 14219 if (idx != 0) 14220 goto error; 14221 } 14222 14223 (void)ga_grow(&ga, cplen); 14224 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen); 14225 ga.ga_len += cplen; 14226 14227 in_str += inlen; 14228 } 14229 else 14230 { 14231 /* When not using multi-byte chars we can do it faster. */ 14232 p = vim_strchr(fromstr, *in_str); 14233 if (p != NULL) 14234 ga_append(&ga, tostr[p - fromstr]); 14235 else 14236 ga_append(&ga, *in_str); 14237 ++in_str; 14238 } 14239 } 14240 14241 /* add a terminating NUL */ 14242 (void)ga_grow(&ga, 1); 14243 ga_append(&ga, NUL); 14244 14245 rettv->vval.v_string = ga.ga_data; 14246 } 14247 14248 /* 14249 * "trim({expr})" function 14250 */ 14251 static void 14252 f_trim(typval_T *argvars, typval_T *rettv) 14253 { 14254 char_u buf1[NUMBUFLEN]; 14255 char_u buf2[NUMBUFLEN]; 14256 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1); 14257 char_u *mask = NULL; 14258 char_u *tail; 14259 char_u *prev; 14260 char_u *p; 14261 int c1; 14262 14263 rettv->v_type = VAR_STRING; 14264 if (head == NULL) 14265 { 14266 rettv->vval.v_string = NULL; 14267 return; 14268 } 14269 14270 if (argvars[1].v_type == VAR_STRING) 14271 mask = tv_get_string_buf_chk(&argvars[1], buf2); 14272 14273 while (*head != NUL) 14274 { 14275 c1 = PTR2CHAR(head); 14276 if (mask == NULL) 14277 { 14278 if (c1 > ' ' && c1 != 0xa0) 14279 break; 14280 } 14281 else 14282 { 14283 for (p = mask; *p != NUL; MB_PTR_ADV(p)) 14284 if (c1 == PTR2CHAR(p)) 14285 break; 14286 if (*p == NUL) 14287 break; 14288 } 14289 MB_PTR_ADV(head); 14290 } 14291 14292 for (tail = head + STRLEN(head); tail > head; tail = prev) 14293 { 14294 prev = tail; 14295 MB_PTR_BACK(head, prev); 14296 c1 = PTR2CHAR(prev); 14297 if (mask == NULL) 14298 { 14299 if (c1 > ' ' && c1 != 0xa0) 14300 break; 14301 } 14302 else 14303 { 14304 for (p = mask; *p != NUL; MB_PTR_ADV(p)) 14305 if (c1 == PTR2CHAR(p)) 14306 break; 14307 if (*p == NUL) 14308 break; 14309 } 14310 } 14311 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head)); 14312 } 14313 14314 #ifdef FEAT_FLOAT 14315 /* 14316 * "trunc({float})" function 14317 */ 14318 static void 14319 f_trunc(typval_T *argvars, typval_T *rettv) 14320 { 14321 float_T f = 0.0; 14322 14323 rettv->v_type = VAR_FLOAT; 14324 if (get_float_arg(argvars, &f) == OK) 14325 /* trunc() is not in C90, use floor() or ceil() instead. */ 14326 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f); 14327 else 14328 rettv->vval.v_float = 0.0; 14329 } 14330 #endif 14331 14332 /* 14333 * "type(expr)" function 14334 */ 14335 static void 14336 f_type(typval_T *argvars, typval_T *rettv) 14337 { 14338 int n = -1; 14339 14340 switch (argvars[0].v_type) 14341 { 14342 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break; 14343 case VAR_STRING: n = VAR_TYPE_STRING; break; 14344 case VAR_PARTIAL: 14345 case VAR_FUNC: n = VAR_TYPE_FUNC; break; 14346 case VAR_LIST: n = VAR_TYPE_LIST; break; 14347 case VAR_DICT: n = VAR_TYPE_DICT; break; 14348 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break; 14349 case VAR_SPECIAL: 14350 if (argvars[0].vval.v_number == VVAL_FALSE 14351 || argvars[0].vval.v_number == VVAL_TRUE) 14352 n = VAR_TYPE_BOOL; 14353 else 14354 n = VAR_TYPE_NONE; 14355 break; 14356 case VAR_JOB: n = VAR_TYPE_JOB; break; 14357 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break; 14358 case VAR_BLOB: n = VAR_TYPE_BLOB; break; 14359 case VAR_UNKNOWN: 14360 internal_error("f_type(UNKNOWN)"); 14361 n = -1; 14362 break; 14363 } 14364 rettv->vval.v_number = n; 14365 } 14366 14367 /* 14368 * "undofile(name)" function 14369 */ 14370 static void 14371 f_undofile(typval_T *argvars UNUSED, typval_T *rettv) 14372 { 14373 rettv->v_type = VAR_STRING; 14374 #ifdef FEAT_PERSISTENT_UNDO 14375 { 14376 char_u *fname = tv_get_string(&argvars[0]); 14377 14378 if (*fname == NUL) 14379 { 14380 /* If there is no file name there will be no undo file. */ 14381 rettv->vval.v_string = NULL; 14382 } 14383 else 14384 { 14385 char_u *ffname = FullName_save(fname, FALSE); 14386 14387 if (ffname != NULL) 14388 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE); 14389 vim_free(ffname); 14390 } 14391 } 14392 #else 14393 rettv->vval.v_string = NULL; 14394 #endif 14395 } 14396 14397 /* 14398 * "undotree()" function 14399 */ 14400 static void 14401 f_undotree(typval_T *argvars UNUSED, typval_T *rettv) 14402 { 14403 if (rettv_dict_alloc(rettv) == OK) 14404 { 14405 dict_T *dict = rettv->vval.v_dict; 14406 list_T *list; 14407 14408 dict_add_number(dict, "synced", (long)curbuf->b_u_synced); 14409 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last); 14410 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last); 14411 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur); 14412 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur); 14413 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur); 14414 14415 list = list_alloc(); 14416 if (list != NULL) 14417 { 14418 u_eval_tree(curbuf->b_u_oldhead, list); 14419 dict_add_list(dict, "entries", list); 14420 } 14421 } 14422 } 14423 14424 /* 14425 * "values(dict)" function 14426 */ 14427 static void 14428 f_values(typval_T *argvars, typval_T *rettv) 14429 { 14430 dict_list(argvars, rettv, 1); 14431 } 14432 14433 /* 14434 * "virtcol(string)" function 14435 */ 14436 static void 14437 f_virtcol(typval_T *argvars, typval_T *rettv) 14438 { 14439 colnr_T vcol = 0; 14440 pos_T *fp; 14441 int fnum = curbuf->b_fnum; 14442 14443 fp = var2fpos(&argvars[0], FALSE, &fnum); 14444 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count 14445 && fnum == curbuf->b_fnum) 14446 { 14447 getvvcol(curwin, fp, NULL, NULL, &vcol); 14448 ++vcol; 14449 } 14450 14451 rettv->vval.v_number = vcol; 14452 } 14453 14454 /* 14455 * "visualmode()" function 14456 */ 14457 static void 14458 f_visualmode(typval_T *argvars, typval_T *rettv) 14459 { 14460 char_u str[2]; 14461 14462 rettv->v_type = VAR_STRING; 14463 str[0] = curbuf->b_visual_mode_eval; 14464 str[1] = NUL; 14465 rettv->vval.v_string = vim_strsave(str); 14466 14467 /* A non-zero number or non-empty string argument: reset mode. */ 14468 if (non_zero_arg(&argvars[0])) 14469 curbuf->b_visual_mode_eval = NUL; 14470 } 14471 14472 /* 14473 * "wildmenumode()" function 14474 */ 14475 static void 14476 f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 14477 { 14478 #ifdef FEAT_WILDMENU 14479 if (wild_menu_showing) 14480 rettv->vval.v_number = 1; 14481 #endif 14482 } 14483 14484 /* 14485 * "winbufnr(nr)" function 14486 */ 14487 static void 14488 f_winbufnr(typval_T *argvars, typval_T *rettv) 14489 { 14490 win_T *wp; 14491 14492 wp = find_win_by_nr_or_id(&argvars[0]); 14493 if (wp == NULL) 14494 rettv->vval.v_number = -1; 14495 else 14496 rettv->vval.v_number = wp->w_buffer->b_fnum; 14497 } 14498 14499 /* 14500 * "wincol()" function 14501 */ 14502 static void 14503 f_wincol(typval_T *argvars UNUSED, typval_T *rettv) 14504 { 14505 validate_cursor(); 14506 rettv->vval.v_number = curwin->w_wcol + 1; 14507 } 14508 14509 /* 14510 * "winheight(nr)" function 14511 */ 14512 static void 14513 f_winheight(typval_T *argvars, typval_T *rettv) 14514 { 14515 win_T *wp; 14516 14517 wp = find_win_by_nr_or_id(&argvars[0]); 14518 if (wp == NULL) 14519 rettv->vval.v_number = -1; 14520 else 14521 rettv->vval.v_number = wp->w_height; 14522 } 14523 14524 /* 14525 * "winlayout()" function 14526 */ 14527 static void 14528 f_winlayout(typval_T *argvars, typval_T *rettv) 14529 { 14530 tabpage_T *tp; 14531 14532 if (rettv_list_alloc(rettv) != OK) 14533 return; 14534 14535 if (argvars[0].v_type == VAR_UNKNOWN) 14536 tp = curtab; 14537 else 14538 { 14539 tp = find_tabpage((int)tv_get_number(&argvars[0])); 14540 if (tp == NULL) 14541 return; 14542 } 14543 14544 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE); 14545 } 14546 14547 /* 14548 * "winline()" function 14549 */ 14550 static void 14551 f_winline(typval_T *argvars UNUSED, typval_T *rettv) 14552 { 14553 validate_cursor(); 14554 rettv->vval.v_number = curwin->w_wrow + 1; 14555 } 14556 14557 /* 14558 * "winnr()" function 14559 */ 14560 static void 14561 f_winnr(typval_T *argvars UNUSED, typval_T *rettv) 14562 { 14563 int nr = 1; 14564 14565 nr = get_winnr(curtab, &argvars[0]); 14566 rettv->vval.v_number = nr; 14567 } 14568 14569 /* 14570 * "winrestcmd()" function 14571 */ 14572 static void 14573 f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv) 14574 { 14575 win_T *wp; 14576 int winnr = 1; 14577 garray_T ga; 14578 char_u buf[50]; 14579 14580 ga_init2(&ga, (int)sizeof(char), 70); 14581 FOR_ALL_WINDOWS(wp) 14582 { 14583 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height); 14584 ga_concat(&ga, buf); 14585 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width); 14586 ga_concat(&ga, buf); 14587 ++winnr; 14588 } 14589 ga_append(&ga, NUL); 14590 14591 rettv->vval.v_string = ga.ga_data; 14592 rettv->v_type = VAR_STRING; 14593 } 14594 14595 /* 14596 * "winrestview()" function 14597 */ 14598 static void 14599 f_winrestview(typval_T *argvars, typval_T *rettv UNUSED) 14600 { 14601 dict_T *dict; 14602 14603 if (argvars[0].v_type != VAR_DICT 14604 || (dict = argvars[0].vval.v_dict) == NULL) 14605 emsg(_(e_invarg)); 14606 else 14607 { 14608 if (dict_find(dict, (char_u *)"lnum", -1) != NULL) 14609 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum"); 14610 if (dict_find(dict, (char_u *)"col", -1) != NULL) 14611 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col"); 14612 if (dict_find(dict, (char_u *)"coladd", -1) != NULL) 14613 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd"); 14614 if (dict_find(dict, (char_u *)"curswant", -1) != NULL) 14615 { 14616 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant"); 14617 curwin->w_set_curswant = FALSE; 14618 } 14619 14620 if (dict_find(dict, (char_u *)"topline", -1) != NULL) 14621 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline")); 14622 #ifdef FEAT_DIFF 14623 if (dict_find(dict, (char_u *)"topfill", -1) != NULL) 14624 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill"); 14625 #endif 14626 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL) 14627 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol"); 14628 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL) 14629 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol"); 14630 14631 check_cursor(); 14632 win_new_height(curwin, curwin->w_height); 14633 win_new_width(curwin, curwin->w_width); 14634 changed_window_setting(); 14635 14636 if (curwin->w_topline <= 0) 14637 curwin->w_topline = 1; 14638 if (curwin->w_topline > curbuf->b_ml.ml_line_count) 14639 curwin->w_topline = curbuf->b_ml.ml_line_count; 14640 #ifdef FEAT_DIFF 14641 check_topfill(curwin, TRUE); 14642 #endif 14643 } 14644 } 14645 14646 /* 14647 * "winsaveview()" function 14648 */ 14649 static void 14650 f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv) 14651 { 14652 dict_T *dict; 14653 14654 if (rettv_dict_alloc(rettv) == FAIL) 14655 return; 14656 dict = rettv->vval.v_dict; 14657 14658 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum); 14659 dict_add_number(dict, "col", (long)curwin->w_cursor.col); 14660 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd); 14661 update_curswant(); 14662 dict_add_number(dict, "curswant", (long)curwin->w_curswant); 14663 14664 dict_add_number(dict, "topline", (long)curwin->w_topline); 14665 #ifdef FEAT_DIFF 14666 dict_add_number(dict, "topfill", (long)curwin->w_topfill); 14667 #endif 14668 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol); 14669 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol); 14670 } 14671 14672 /* 14673 * "winwidth(nr)" function 14674 */ 14675 static void 14676 f_winwidth(typval_T *argvars, typval_T *rettv) 14677 { 14678 win_T *wp; 14679 14680 wp = find_win_by_nr_or_id(&argvars[0]); 14681 if (wp == NULL) 14682 rettv->vval.v_number = -1; 14683 else 14684 rettv->vval.v_number = wp->w_width; 14685 } 14686 14687 /* 14688 * "wordcount()" function 14689 */ 14690 static void 14691 f_wordcount(typval_T *argvars UNUSED, typval_T *rettv) 14692 { 14693 if (rettv_dict_alloc(rettv) == FAIL) 14694 return; 14695 cursor_pos_info(rettv->vval.v_dict); 14696 } 14697 14698 /* 14699 * "writefile()" function 14700 */ 14701 static void 14702 f_writefile(typval_T *argvars, typval_T *rettv) 14703 { 14704 int binary = FALSE; 14705 int append = FALSE; 14706 #ifdef HAVE_FSYNC 14707 int do_fsync = p_fs; 14708 #endif 14709 char_u *fname; 14710 FILE *fd; 14711 int ret = 0; 14712 listitem_T *li; 14713 list_T *list = NULL; 14714 blob_T *blob = NULL; 14715 14716 rettv->vval.v_number = -1; 14717 if (check_restricted() || check_secure()) 14718 return; 14719 14720 if (argvars[0].v_type == VAR_LIST) 14721 { 14722 list = argvars[0].vval.v_list; 14723 if (list == NULL) 14724 return; 14725 for (li = list->lv_first; li != NULL; li = li->li_next) 14726 if (tv_get_string_chk(&li->li_tv) == NULL) 14727 return; 14728 } 14729 else if (argvars[0].v_type == VAR_BLOB) 14730 { 14731 blob = argvars[0].vval.v_blob; 14732 if (blob == NULL) 14733 return; 14734 } 14735 else 14736 { 14737 semsg(_(e_invarg2), "writefile()"); 14738 return; 14739 } 14740 14741 if (argvars[2].v_type != VAR_UNKNOWN) 14742 { 14743 char_u *arg2 = tv_get_string_chk(&argvars[2]); 14744 14745 if (arg2 == NULL) 14746 return; 14747 if (vim_strchr(arg2, 'b') != NULL) 14748 binary = TRUE; 14749 if (vim_strchr(arg2, 'a') != NULL) 14750 append = TRUE; 14751 #ifdef HAVE_FSYNC 14752 if (vim_strchr(arg2, 's') != NULL) 14753 do_fsync = TRUE; 14754 else if (vim_strchr(arg2, 'S') != NULL) 14755 do_fsync = FALSE; 14756 #endif 14757 } 14758 14759 fname = tv_get_string_chk(&argvars[1]); 14760 if (fname == NULL) 14761 return; 14762 14763 /* Always open the file in binary mode, library functions have a mind of 14764 * their own about CR-LF conversion. */ 14765 if (*fname == NUL || (fd = mch_fopen((char *)fname, 14766 append ? APPENDBIN : WRITEBIN)) == NULL) 14767 { 14768 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname); 14769 ret = -1; 14770 } 14771 else if (blob) 14772 { 14773 if (write_blob(fd, blob) == FAIL) 14774 ret = -1; 14775 #ifdef HAVE_FSYNC 14776 else if (do_fsync) 14777 // Ignore the error, the user wouldn't know what to do about it. 14778 // May happen for a device. 14779 vim_ignored = fsync(fileno(fd)); 14780 #endif 14781 fclose(fd); 14782 } 14783 else 14784 { 14785 if (write_list(fd, list, binary) == FAIL) 14786 ret = -1; 14787 #ifdef HAVE_FSYNC 14788 else if (do_fsync) 14789 /* Ignore the error, the user wouldn't know what to do about it. 14790 * May happen for a device. */ 14791 vim_ignored = fsync(fileno(fd)); 14792 #endif 14793 fclose(fd); 14794 } 14795 14796 rettv->vval.v_number = ret; 14797 } 14798 14799 /* 14800 * "xor(expr, expr)" function 14801 */ 14802 static void 14803 f_xor(typval_T *argvars, typval_T *rettv) 14804 { 14805 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL) 14806 ^ tv_get_number_chk(&argvars[1], NULL); 14807 } 14808 14809 #endif /* FEAT_EVAL */ 14810