blob: 5418804c5802466d0022d9a3800540cac9545bb6 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
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 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010017static void cmd_source(char_u *fname, exarg_T *eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +000018
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
69static int debug_greedy = FALSE; /* batch mode debugging: don't save
70 and restore typeahead. */
Bram Moolenaarf1f60f82016-01-16 15:40:53 +010071static void do_setdebugtracelevel(char_u *arg);
72static void do_checkbacktracelevel(void);
73static void do_showbacktrace(char_u *cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +000074
Bram Moolenaarc6f9f732018-02-11 19:06:26 +010075static char_u *debug_oldval = NULL; /* old and newval for debug expressions */
76static char_u *debug_newval = NULL;
77static int debug_expr = 0; /* use debug_expr */
78
79 int
80has_watchexpr(void)
81{
82 return debug_expr;
83}
84
Bram Moolenaar071d4272004-06-13 20:20:40 +000085/*
86 * do_debug(): Debug mode.
87 * Repeatedly get Ex commands, until told to continue normal execution.
88 */
89 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010090do_debug(char_u *cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +000091{
92 int save_msg_scroll = msg_scroll;
93 int save_State = State;
94 int save_did_emsg = did_emsg;
95 int save_cmd_silent = cmd_silent;
96 int save_msg_silent = msg_silent;
97 int save_emsg_silent = emsg_silent;
98 int save_redir_off = redir_off;
99 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000100 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +0000101 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000102 int save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000103 int n;
104 char_u *cmdline = NULL;
105 char_u *p;
106 char *tail = NULL;
107 static int last_cmd = 0;
108#define CMD_CONT 1
109#define CMD_NEXT 2
110#define CMD_STEP 3
111#define CMD_FINISH 4
112#define CMD_QUIT 5
113#define CMD_INTERRUPT 6
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100114#define CMD_BACKTRACE 7
115#define CMD_FRAME 8
116#define CMD_UP 9
117#define CMD_DOWN 10
Bram Moolenaar071d4272004-06-13 20:20:40 +0000118
119#ifdef ALWAYS_USE_GUI
120 /* Can't do this when there is no terminal for input/output. */
121 if (!gui.in_use)
122 {
123 /* Break as soon as possible. */
124 debug_break_level = 9999;
125 return;
126 }
127#endif
128
129 /* Make sure we are in raw mode and start termcap mode. Might have side
130 * effects... */
131 settmode(TMODE_RAW);
132 starttermcap();
133
134 ++RedrawingDisabled; /* don't redisplay the window */
135 ++no_wait_return; /* don't wait for return */
136 did_emsg = FALSE; /* don't use error from debugged stuff */
137 cmd_silent = FALSE; /* display commands */
138 msg_silent = FALSE; /* display messages */
139 emsg_silent = FALSE; /* display error messages */
140 redir_off = TRUE; /* don't redirect debug commands */
141
142 State = NORMAL;
Bram Moolenaard99388b2017-10-26 14:28:32 +0200143 debug_mode = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144
145 if (!debug_did_msg)
Bram Moolenaar32526b32019-01-19 17:43:09 +0100146 msg(_("Entering Debug mode. Type \"cont\" to continue."));
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100147 if (debug_oldval != NULL)
148 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100149 smsg(_("Oldval = \"%s\""), debug_oldval);
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100150 vim_free(debug_oldval);
151 debug_oldval = NULL;
152 }
153 if (debug_newval != NULL)
154 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100155 smsg(_("Newval = \"%s\""), debug_newval);
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100156 vim_free(debug_newval);
157 debug_newval = NULL;
158 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000159 if (sourcing_name != NULL)
Bram Moolenaar32526b32019-01-19 17:43:09 +0100160 msg((char *)sourcing_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161 if (sourcing_lnum != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100162 smsg(_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000163 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100164 smsg(_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165 /*
166 * Repeat getting a command and executing it.
167 */
168 for (;;)
169 {
170 msg_scroll = TRUE;
171 need_wait_return = FALSE;
Bram Moolenaar85b11762016-02-27 18:13:23 +0100172
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173 /* Save the current typeahead buffer and replace it with an empty one.
174 * This makes sure we get input from the user here and don't interfere
175 * with the commands being executed. Reset "ex_normal_busy" to avoid
176 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000177 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000178 save_ex_normal_busy = ex_normal_busy;
179 ex_normal_busy = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000181 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000182 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000183 typeahead_saved = TRUE;
184 save_ignore_script = ignore_script;
185 ignore_script = TRUE;
186 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000187
Bram Moolenaardc303bc2016-05-17 17:45:38 +0200188 vim_free(cmdline);
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000189 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000190
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000191 if (typeahead_saved)
192 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000193 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000194 ignore_script = save_ignore_script;
195 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196 ex_normal_busy = save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000197
198 cmdline_row = msg_row;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100199 msg_starthere();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000200 if (cmdline != NULL)
201 {
202 /* If this is a debug command, set "last_cmd".
203 * If not, reset "last_cmd".
204 * For a blank line use previous command. */
205 p = skipwhite(cmdline);
206 if (*p != NUL)
207 {
208 switch (*p)
209 {
210 case 'c': last_cmd = CMD_CONT;
211 tail = "ont";
212 break;
213 case 'n': last_cmd = CMD_NEXT;
214 tail = "ext";
215 break;
216 case 's': last_cmd = CMD_STEP;
217 tail = "tep";
218 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100219 case 'f':
220 last_cmd = 0;
221 if (p[1] == 'r')
222 {
223 last_cmd = CMD_FRAME;
224 tail = "rame";
225 }
226 else
227 {
228 last_cmd = CMD_FINISH;
229 tail = "inish";
230 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000231 break;
232 case 'q': last_cmd = CMD_QUIT;
233 tail = "uit";
234 break;
235 case 'i': last_cmd = CMD_INTERRUPT;
236 tail = "nterrupt";
237 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100238 case 'b': last_cmd = CMD_BACKTRACE;
239 if (p[1] == 't')
240 tail = "t";
241 else
242 tail = "acktrace";
243 break;
244 case 'w': last_cmd = CMD_BACKTRACE;
245 tail = "here";
246 break;
247 case 'u': last_cmd = CMD_UP;
248 tail = "p";
249 break;
250 case 'd': last_cmd = CMD_DOWN;
251 tail = "own";
252 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000253 default: last_cmd = 0;
254 }
255 if (last_cmd != 0)
256 {
257 /* Check that the tail matches. */
258 ++p;
259 while (*p != NUL && *p == *tail)
260 {
261 ++p;
262 ++tail;
263 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100264 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000265 last_cmd = 0;
266 }
267 }
268
269 if (last_cmd != 0)
270 {
271 /* Execute debug command: decided where to break next and
272 * return. */
273 switch (last_cmd)
274 {
275 case CMD_CONT:
276 debug_break_level = -1;
277 break;
278 case CMD_NEXT:
279 debug_break_level = ex_nesting_level;
280 break;
281 case CMD_STEP:
282 debug_break_level = 9999;
283 break;
284 case CMD_FINISH:
285 debug_break_level = ex_nesting_level - 1;
286 break;
287 case CMD_QUIT:
288 got_int = TRUE;
289 debug_break_level = -1;
290 break;
291 case CMD_INTERRUPT:
292 got_int = TRUE;
293 debug_break_level = 9999;
294 /* Do not repeat ">interrupt" cmd, continue stepping. */
295 last_cmd = CMD_STEP;
296 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100297 case CMD_BACKTRACE:
298 do_showbacktrace(cmd);
299 continue;
300 case CMD_FRAME:
301 if (*p == NUL)
302 {
303 do_showbacktrace(cmd);
304 }
305 else
306 {
307 p = skipwhite(p);
308 do_setdebugtracelevel(p);
309 }
310 continue;
311 case CMD_UP:
312 debug_backtrace_level++;
313 do_checkbacktracelevel();
314 continue;
315 case CMD_DOWN:
316 debug_backtrace_level--;
317 do_checkbacktracelevel();
318 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000319 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100320 /* Going out reset backtrace_level */
321 debug_backtrace_level = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000322 break;
323 }
324
325 /* don't debug this command */
326 n = debug_break_level;
327 debug_break_level = -1;
328 (void)do_cmdline(cmdline, getexline, NULL,
329 DOCMD_VERBOSE|DOCMD_EXCRESET);
330 debug_break_level = n;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000331 }
332 lines_left = Rows - 1;
333 }
334 vim_free(cmdline);
335
336 --RedrawingDisabled;
337 --no_wait_return;
338 redraw_all_later(NOT_VALID);
339 need_wait_return = FALSE;
340 msg_scroll = save_msg_scroll;
341 lines_left = Rows - 1;
342 State = save_State;
Bram Moolenaard99388b2017-10-26 14:28:32 +0200343 debug_mode = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000344 did_emsg = save_did_emsg;
345 cmd_silent = save_cmd_silent;
346 msg_silent = save_msg_silent;
347 emsg_silent = save_emsg_silent;
348 redir_off = save_redir_off;
349
350 /* Only print the message again when typing a command before coming back
351 * here. */
352 debug_did_msg = TRUE;
353}
354
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100355 static int
356get_maxbacktrace_level(void)
357{
358 char *p, *q;
Bram Moolenaardc633cf2016-04-23 14:33:19 +0200359 int maxbacktrace = 0;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100360
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100361 if (sourcing_name != NULL)
362 {
363 p = (char *)sourcing_name;
364 while ((q = strstr(p, "..")) != NULL)
365 {
366 p = q + 2;
367 maxbacktrace++;
368 }
369 }
370 return maxbacktrace;
371}
372
373 static void
374do_setdebugtracelevel(char_u *arg)
375{
376 int level;
377
378 level = atoi((char *)arg);
379 if (*arg == '+' || level < 0)
380 debug_backtrace_level += level;
381 else
382 debug_backtrace_level = level;
383
384 do_checkbacktracelevel();
385}
386
387 static void
388do_checkbacktracelevel(void)
389{
390 if (debug_backtrace_level < 0)
391 {
392 debug_backtrace_level = 0;
Bram Moolenaar32526b32019-01-19 17:43:09 +0100393 msg(_("frame is zero"));
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100394 }
395 else
396 {
397 int max = get_maxbacktrace_level();
398
399 if (debug_backtrace_level > max)
400 {
401 debug_backtrace_level = max;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100402 smsg(_("frame at highest level: %d"), max);
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100403 }
404 }
405}
406
407 static void
408do_showbacktrace(char_u *cmd)
409{
410 char *cur;
411 char *next;
412 int i = 0;
413 int max = get_maxbacktrace_level();
414
415 if (sourcing_name != NULL)
416 {
417 cur = (char *)sourcing_name;
418 while (!got_int)
419 {
420 next = strstr(cur, "..");
421 if (next != NULL)
422 *next = NUL;
423 if (i == max - debug_backtrace_level)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100424 smsg("->%d %s", max - i, cur);
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100425 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100426 smsg(" %d %s", max - i, cur);
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100427 ++i;
428 if (next == NULL)
429 break;
430 *next = '.';
431 cur = next + 2;
432 }
433 }
434 if (sourcing_lnum != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100435 smsg(_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100436 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100437 smsg(_("cmd: %s"), cmd);
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100438}
439
Bram Moolenaar071d4272004-06-13 20:20:40 +0000440/*
441 * ":debug".
442 */
443 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100444ex_debug(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000445{
446 int debug_break_level_save = debug_break_level;
447
448 debug_break_level = 9999;
449 do_cmdline_cmd(eap->arg);
450 debug_break_level = debug_break_level_save;
451}
452
453static char_u *debug_breakpoint_name = NULL;
454static linenr_T debug_breakpoint_lnum;
455
456/*
457 * When debugging or a breakpoint is set on a skipped command, no debug prompt
458 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
459 * debug_skipped_name is then set to the source name in the breakpoint case. If
460 * a skipped command decides itself that a debug prompt should be displayed, it
461 * can do so by calling dbg_check_skipped().
462 */
463static int debug_skipped;
464static char_u *debug_skipped_name;
465
466/*
467 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
468 * at or below the break level. But only when the line is actually
469 * executed. Return TRUE and set breakpoint_name for skipped commands that
470 * decide to execute something themselves.
471 * Called from do_one_cmd() before executing a command.
472 */
473 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100474dbg_check_breakpoint(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000475{
476 char_u *p;
477
478 debug_skipped = FALSE;
479 if (debug_breakpoint_name != NULL)
480 {
481 if (!eap->skip)
482 {
483 /* replace K_SNR with "<SNR>" */
484 if (debug_breakpoint_name[0] == K_SPECIAL
485 && debug_breakpoint_name[1] == KS_EXTRA
486 && debug_breakpoint_name[2] == (int)KE_SNR)
487 p = (char_u *)"<SNR>";
488 else
489 p = (char_u *)"";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100490 smsg(_("Breakpoint in \"%s%s\" line %ld"),
Bram Moolenaar555b2802005-05-19 21:08:39 +0000491 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000492 debug_breakpoint_name + (*p == NUL ? 0 : 3),
493 (long)debug_breakpoint_lnum);
494 debug_breakpoint_name = NULL;
495 do_debug(eap->cmd);
496 }
497 else
498 {
499 debug_skipped = TRUE;
500 debug_skipped_name = debug_breakpoint_name;
501 debug_breakpoint_name = NULL;
502 }
503 }
504 else if (ex_nesting_level <= debug_break_level)
505 {
506 if (!eap->skip)
507 do_debug(eap->cmd);
508 else
509 {
510 debug_skipped = TRUE;
511 debug_skipped_name = NULL;
512 }
513 }
514}
515
516/*
517 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
518 * set. Return TRUE when the debug mode is entered this time.
519 */
520 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100521dbg_check_skipped(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000522{
523 int prev_got_int;
524
525 if (debug_skipped)
526 {
527 /*
528 * Save the value of got_int and reset it. We don't want a previous
529 * interruption cause flushing the input buffer.
530 */
531 prev_got_int = got_int;
532 got_int = FALSE;
533 debug_breakpoint_name = debug_skipped_name;
534 /* eap->skip is TRUE */
535 eap->skip = FALSE;
536 (void)dbg_check_breakpoint(eap);
537 eap->skip = TRUE;
538 got_int |= prev_got_int;
539 return TRUE;
540 }
541 return FALSE;
542}
543
544/*
545 * The list of breakpoints: dbg_breakp.
546 * This is a grow-array of structs.
547 */
548struct debuggy
549{
550 int dbg_nr; /* breakpoint number */
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100551 int dbg_type; /* DBG_FUNC, DBG_FILE or DBG_EXPR */
552 char_u *dbg_name; /* function, expression or file name */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553 regprog_T *dbg_prog; /* regexp program */
554 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000555 int dbg_forceit; /* ! used */
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100556#ifdef FEAT_EVAL
557 typval_T *dbg_val; /* last result of watchexpression */
558#endif
559 int dbg_level; /* stored nested level for expr */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000560};
561
562static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000563#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
564#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565static int last_breakp = 0; /* nr of last defined breakpoint */
566
Bram Moolenaar05159a02005-02-26 23:04:13 +0000567#ifdef FEAT_PROFILE
568/* Profiling uses file and func names similar to breakpoints. */
569static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
570#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000571#define DBG_FUNC 1
572#define DBG_FILE 2
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100573#define DBG_EXPR 3
Bram Moolenaar071d4272004-06-13 20:20:40 +0000574
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100575static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000576
577/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000578 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
579 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
580 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000581 * Returns FAIL for failure.
582 */
583 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100584dbg_parsearg(
585 char_u *arg,
586 garray_T *gap) /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000587{
588 char_u *p = arg;
589 char_u *q;
590 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000591 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000592
Bram Moolenaar05159a02005-02-26 23:04:13 +0000593 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000595 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596
597 /* Find "func" or "file". */
598 if (STRNCMP(p, "func", 4) == 0)
599 bp->dbg_type = DBG_FUNC;
600 else if (STRNCMP(p, "file", 4) == 0)
601 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000602 else if (
603#ifdef FEAT_PROFILE
604 gap != &prof_ga &&
605#endif
606 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000607 {
608 if (curbuf->b_ffname == NULL)
609 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100610 emsg(_(e_noname));
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000611 return FAIL;
612 }
613 bp->dbg_type = DBG_FILE;
614 here = TRUE;
615 }
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100616 else if (
617#ifdef FEAT_PROFILE
618 gap != &prof_ga &&
619#endif
620 STRNCMP(p, "expr", 4) == 0)
621 bp->dbg_type = DBG_EXPR;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622 else
623 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100624 semsg(_(e_invarg2), p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 return FAIL;
626 }
627 p = skipwhite(p + 4);
628
629 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000630 if (here)
631 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000632 else if (
633#ifdef FEAT_PROFILE
634 gap != &prof_ga &&
635#endif
636 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000637 {
638 bp->dbg_lnum = getdigits(&p);
639 p = skipwhite(p);
640 }
641 else
642 bp->dbg_lnum = 0;
643
644 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000645 if ((!here && *p == NUL)
646 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
648 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100649 semsg(_(e_invarg2), arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000650 return FAIL;
651 }
652
653 if (bp->dbg_type == DBG_FUNC)
654 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000655 else if (here)
656 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100657 else if (bp->dbg_type == DBG_EXPR)
658 {
659 bp->dbg_name = vim_strsave(p);
660 if (bp->dbg_name != NULL)
661 bp->dbg_val = eval_expr(bp->dbg_name, NULL);
662 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000663 else
664 {
665 /* Expand the file name in the same way as do_source(). This means
666 * doing it twice, so that $DIR/file gets expanded when $DIR is
667 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000669 if (q == NULL)
670 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000671 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672 vim_free(q);
673 if (p == NULL)
674 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000675 if (*p != '*')
676 {
677 bp->dbg_name = fix_fname(p);
678 vim_free(p);
679 }
680 else
681 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000682 }
683
684 if (bp->dbg_name == NULL)
685 return FAIL;
686 return OK;
687}
688
689/*
Bram Moolenaare0be1672018-07-08 16:50:37 +0200690 * ":breakadd". Also used for ":profile".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000691 */
692 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100693ex_breakadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000694{
695 struct debuggy *bp;
696 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000697 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000698
Bram Moolenaar05159a02005-02-26 23:04:13 +0000699 gap = &dbg_breakp;
700#ifdef FEAT_PROFILE
701 if (eap->cmdidx == CMD_profile)
702 gap = &prof_ga;
703#endif
704
705 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000706 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000707 bp = &DEBUGGY(gap, gap->ga_len);
708 bp->dbg_forceit = eap->forceit;
709
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100710 if (bp->dbg_type != DBG_EXPR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100712 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
713 if (pat != NULL)
714 {
715 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
716 vim_free(pat);
717 }
718 if (pat == NULL || bp->dbg_prog == NULL)
719 vim_free(bp->dbg_name);
720 else
721 {
722 if (bp->dbg_lnum == 0) /* default line number is 1 */
723 bp->dbg_lnum = 1;
724#ifdef FEAT_PROFILE
725 if (eap->cmdidx != CMD_profile)
726#endif
727 {
728 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
729 ++debug_tick;
730 }
731 ++gap->ga_len;
732 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000733 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 else
735 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100736 /* DBG_EXPR */
737 DEBUGGY(gap, gap->ga_len++).dbg_nr = ++last_breakp;
738 ++debug_tick;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 }
740 }
741}
742
743/*
744 * ":debuggreedy".
745 */
746 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100747ex_debuggreedy(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748{
749 if (eap->addr_count == 0 || eap->line2 != 0)
750 debug_greedy = TRUE;
751 else
752 debug_greedy = FALSE;
753}
754
755/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000756 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757 */
758 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100759ex_breakdel(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000760{
761 struct debuggy *bp, *bpi;
762 int nr;
763 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000764 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765 int i;
766 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000767 garray_T *gap;
768
769 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000770 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200771 {
772#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000773 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200774#else
775 ex_ni(eap);
776 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000777#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200778 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779
780 if (vim_isdigit(*eap->arg))
781 {
782 /* ":breakdel {nr}" */
783 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000784 for (i = 0; i < gap->ga_len; ++i)
785 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000786 {
787 todel = i;
788 break;
789 }
790 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000791 else if (*eap->arg == '*')
792 {
793 todel = 0;
794 del_all = TRUE;
795 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796 else
797 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100798 /* ":breakdel {func|file|expr} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000799 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000801 bp = &DEBUGGY(gap, gap->ga_len);
802 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000804 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000805 if (bp->dbg_type == bpi->dbg_type
806 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
807 && (bp->dbg_lnum == bpi->dbg_lnum
808 || (bp->dbg_lnum == 0
809 && (best_lnum == 0
810 || bpi->dbg_lnum < best_lnum))))
811 {
812 todel = i;
813 best_lnum = bpi->dbg_lnum;
814 }
815 }
816 vim_free(bp->dbg_name);
817 }
818
819 if (todel < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100820 semsg(_("E161: Breakpoint not found: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000822 {
823 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000824 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000825 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100826#ifdef FEAT_EVAL
827 if (DEBUGGY(gap, todel).dbg_type == DBG_EXPR
828 && DEBUGGY(gap, todel).dbg_val != NULL)
829 free_tv(DEBUGGY(gap, todel).dbg_val);
830#endif
Bram Moolenaar473de612013-06-08 18:19:48 +0200831 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000832 --gap->ga_len;
833 if (todel < gap->ga_len)
834 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
835 (gap->ga_len - todel) * sizeof(struct debuggy));
836#ifdef FEAT_PROFILE
837 if (eap->cmdidx == CMD_breakdel)
838#endif
839 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000840 if (!del_all)
841 break;
842 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000843
844 /* If all breakpoints were removed clear the array. */
845 if (gap->ga_len == 0)
846 ga_clear(gap);
847 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848}
849
850/*
851 * ":breaklist".
852 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000853 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100854ex_breaklist(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855{
856 struct debuggy *bp;
857 int i;
858
859 if (dbg_breakp.ga_len == 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +0100860 msg(_("No breakpoints defined"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000861 else
862 for (i = 0; i < dbg_breakp.ga_len; ++i)
863 {
864 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200865 if (bp->dbg_type == DBG_FILE)
866 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100867 if (bp->dbg_type != DBG_EXPR)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100868 smsg(_("%3d %s %s line %ld"),
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 bp->dbg_nr,
870 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200871 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 (long)bp->dbg_lnum);
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100873 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100874 smsg(_("%3d expr %s"),
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100875 bp->dbg_nr, bp->dbg_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 }
877}
878
879/*
880 * Find a breakpoint for a function or sourced file.
881 * Returns line number at which to break; zero when no matching breakpoint.
882 */
883 linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100884dbg_find_breakpoint(
885 int file, /* TRUE for a file, FALSE for a function */
886 char_u *fname, /* file or function name */
887 linenr_T after) /* after this line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000888{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000889 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
890}
891
892#if defined(FEAT_PROFILE) || defined(PROTO)
893/*
894 * Return TRUE if profiling is on for a function or sourced file.
895 */
896 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100897has_profiling(
898 int file, /* TRUE for a file, FALSE for a function */
899 char_u *fname, /* file or function name */
900 int *fp) /* return: forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000901{
902 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
903 != (linenr_T)0);
904}
905#endif
906
907/*
908 * Common code for dbg_find_breakpoint() and has_profiling().
909 */
910 static linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100911debuggy_find(
912 int file, /* TRUE for a file, FALSE for a function */
913 char_u *fname, /* file or function name */
914 linenr_T after, /* after this line number */
915 garray_T *gap, /* either &dbg_breakp or &prof_ga */
916 int *fp) /* if not NULL: return forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000917{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000918 struct debuggy *bp;
919 int i;
920 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000921 char_u *name = fname;
922 int prev_got_int;
923
Bram Moolenaar05159a02005-02-26 23:04:13 +0000924 /* Return quickly when there are no breakpoints. */
925 if (gap->ga_len == 0)
926 return (linenr_T)0;
927
Bram Moolenaar071d4272004-06-13 20:20:40 +0000928 /* Replace K_SNR in function name with "<SNR>". */
929 if (!file && fname[0] == K_SPECIAL)
930 {
931 name = alloc((unsigned)STRLEN(fname) + 3);
932 if (name == NULL)
933 name = fname;
934 else
935 {
936 STRCPY(name, "<SNR>");
937 STRCPY(name + 5, fname + 3);
938 }
939 }
940
Bram Moolenaar05159a02005-02-26 23:04:13 +0000941 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000942 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000943 /* Skip entries that are not useful or are for a line that is beyond
944 * an already found breakpoint. */
945 bp = &DEBUGGY(gap, i);
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100946 if (((bp->dbg_type == DBG_FILE) == file &&
947 bp->dbg_type != DBG_EXPR && (
Bram Moolenaar05159a02005-02-26 23:04:13 +0000948#ifdef FEAT_PROFILE
949 gap == &prof_ga ||
950#endif
951 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000952 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000953 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000954 * Save the value of got_int and reset it. We don't want a
955 * previous interruption cancel matching, only hitting CTRL-C
956 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000957 */
958 prev_got_int = got_int;
959 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100960 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000961 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000962 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000963 if (fp != NULL)
964 *fp = bp->dbg_forceit;
965 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000966 got_int |= prev_got_int;
967 }
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100968#ifdef FEAT_EVAL
969 else if (bp->dbg_type == DBG_EXPR)
970 {
971 typval_T *tv;
972 int line = FALSE;
973
974 prev_got_int = got_int;
975 got_int = FALSE;
976
977 tv = eval_expr(bp->dbg_name, NULL);
978 if (tv != NULL)
979 {
980 if (bp->dbg_val == NULL)
981 {
982 debug_oldval = typval_tostring(NULL);
983 bp->dbg_val = tv;
984 debug_newval = typval_tostring(bp->dbg_val);
985 line = TRUE;
986 }
987 else
988 {
Bram Moolenaar31988702018-02-13 12:57:42 +0100989 if (typval_compare(tv, bp->dbg_val, TYPE_EQUAL,
990 TRUE, FALSE) == OK
991 && tv->vval.v_number == FALSE)
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100992 {
Bram Moolenaar31988702018-02-13 12:57:42 +0100993 typval_T *v;
Bram Moolenaarc6f9f732018-02-11 19:06:26 +0100994
Bram Moolenaar31988702018-02-13 12:57:42 +0100995 line = TRUE;
996 debug_oldval = typval_tostring(bp->dbg_val);
997 /* Need to evaluate again, typval_compare() overwrites
998 * "tv". */
999 v = eval_expr(bp->dbg_name, NULL);
1000 debug_newval = typval_tostring(v);
1001 free_tv(bp->dbg_val);
1002 bp->dbg_val = v;
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01001003 }
1004 free_tv(tv);
1005 }
1006 }
1007 else if (bp->dbg_val != NULL)
1008 {
1009 debug_oldval = typval_tostring(bp->dbg_val);
1010 debug_newval = typval_tostring(NULL);
1011 free_tv(bp->dbg_val);
1012 bp->dbg_val = NULL;
1013 line = TRUE;
1014 }
1015
1016 if (line)
1017 {
1018 lnum = after > 0 ? after : 1;
1019 break;
1020 }
1021
1022 got_int |= prev_got_int;
1023 }
1024#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001025 }
1026 if (name != fname)
1027 vim_free(name);
1028
1029 return lnum;
1030}
1031
1032/*
1033 * Called when a breakpoint was encountered.
1034 */
1035 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001036dbg_breakpoint(char_u *name, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001037{
1038 /* We need to check if this line is actually executed in do_one_cmd() */
1039 debug_breakpoint_name = name;
1040 debug_breakpoint_lnum = lnum;
1041}
Bram Moolenaar05159a02005-02-26 23:04:13 +00001042
1043
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001044# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001045/*
1046 * Store the current time in "tm".
1047 */
1048 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001049profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001050{
Bram Moolenaar4f974752019-02-17 17:44:42 +01001051# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001052 QueryPerformanceCounter(tm);
1053# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001054 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001055# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001056}
1057
1058/*
1059 * Compute the elapsed time from "tm" till now and store in "tm".
1060 */
1061 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001062profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001063{
1064 proftime_T now;
1065
Bram Moolenaar4f974752019-02-17 17:44:42 +01001066# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001067 QueryPerformanceCounter(&now);
1068 tm->QuadPart = now.QuadPart - tm->QuadPart;
1069# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001070 gettimeofday(&now, NULL);
1071 tm->tv_usec = now.tv_usec - tm->tv_usec;
1072 tm->tv_sec = now.tv_sec - tm->tv_sec;
1073 if (tm->tv_usec < 0)
1074 {
1075 tm->tv_usec += 1000000;
1076 --tm->tv_sec;
1077 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001078# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001079}
1080
1081/*
1082 * Subtract the time "tm2" from "tm".
1083 */
1084 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001085profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001086{
Bram Moolenaar4f974752019-02-17 17:44:42 +01001087# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001088 tm->QuadPart -= tm2->QuadPart;
1089# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001090 tm->tv_usec -= tm2->tv_usec;
1091 tm->tv_sec -= tm2->tv_sec;
1092 if (tm->tv_usec < 0)
1093 {
1094 tm->tv_usec += 1000000;
1095 --tm->tv_sec;
1096 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001097# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001098}
1099
1100/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001101 * Return a string that represents the time in "tm".
1102 * Uses a static buffer!
1103 */
1104 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001105profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001106{
1107 static char buf[50];
1108
Bram Moolenaar4f974752019-02-17 17:44:42 +01001109# ifdef MSWIN
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001110 LARGE_INTEGER fr;
1111
1112 QueryPerformanceFrequency(&fr);
1113 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
1114# else
1115 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +00001116# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001117 return buf;
1118}
1119
Bram Moolenaar79c2c882016-02-07 21:19:28 +01001120# if defined(FEAT_FLOAT) || defined(PROTO)
1121/*
1122 * Return a float that represents the time in "tm".
1123 */
1124 float_T
1125profile_float(proftime_T *tm)
1126{
Bram Moolenaar4f974752019-02-17 17:44:42 +01001127# ifdef MSWIN
Bram Moolenaar79c2c882016-02-07 21:19:28 +01001128 LARGE_INTEGER fr;
1129
1130 QueryPerformanceFrequency(&fr);
1131 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
1132# else
1133 return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
1134# endif
1135}
1136# endif
1137
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001138/*
Bram Moolenaar76929292008-01-06 19:07:36 +00001139 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001140 */
Bram Moolenaar76929292008-01-06 19:07:36 +00001141 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001142profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001143{
1144 if (msec <= 0) /* no limit */
1145 profile_zero(tm);
1146 else
1147 {
Bram Moolenaar4f974752019-02-17 17:44:42 +01001148# ifdef MSWIN
Bram Moolenaar76929292008-01-06 19:07:36 +00001149 LARGE_INTEGER fr;
1150
1151 QueryPerformanceCounter(tm);
1152 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001153 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +00001154# else
1155 long usec;
1156
1157 gettimeofday(tm, NULL);
1158 usec = (long)tm->tv_usec + (long)msec * 1000;
1159 tm->tv_usec = usec % 1000000L;
1160 tm->tv_sec += usec / 1000000L;
1161# endif
1162 }
1163}
1164
1165/*
1166 * Return TRUE if the current time is past "tm".
1167 */
1168 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001169profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001170{
1171 proftime_T now;
1172
Bram Moolenaar4f974752019-02-17 17:44:42 +01001173# ifdef MSWIN
Bram Moolenaar76929292008-01-06 19:07:36 +00001174 if (tm->QuadPart == 0) /* timer was not set */
1175 return FALSE;
1176 QueryPerformanceCounter(&now);
1177 return (now.QuadPart > tm->QuadPart);
1178# else
1179 if (tm->tv_sec == 0) /* timer was not set */
1180 return FALSE;
1181 gettimeofday(&now, NULL);
1182 return (now.tv_sec > tm->tv_sec
1183 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
1184# endif
1185}
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001186
1187/*
1188 * Set the time in "tm" to zero.
1189 */
1190 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001191profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001192{
Bram Moolenaar4f974752019-02-17 17:44:42 +01001193# ifdef MSWIN
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001194 tm->QuadPart = 0;
1195# else
1196 tm->tv_usec = 0;
1197 tm->tv_sec = 0;
1198# endif
1199}
1200
Bram Moolenaar76929292008-01-06 19:07:36 +00001201# endif /* FEAT_PROFILE || FEAT_RELTIME */
1202
Bram Moolenaar975b5272016-03-15 23:10:59 +01001203# if defined(FEAT_TIMERS) || defined(PROTO)
1204static timer_T *first_timer = NULL;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001205static long last_timer_id = 0;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001206
Bram Moolenaar56bc8e22018-05-10 18:05:56 +02001207 long
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001208proftime_time_left(proftime_T *due, proftime_T *now)
Bram Moolenaara8e93d62017-09-18 21:50:47 +02001209{
Bram Moolenaar4f974752019-02-17 17:44:42 +01001210# ifdef MSWIN
Bram Moolenaara8e93d62017-09-18 21:50:47 +02001211 LARGE_INTEGER fr;
1212
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001213 if (now->QuadPart > due->QuadPart)
Bram Moolenaara8e93d62017-09-18 21:50:47 +02001214 return 0;
1215 QueryPerformanceFrequency(&fr);
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001216 return (long)(((double)(due->QuadPart - now->QuadPart)
Bram Moolenaara8e93d62017-09-18 21:50:47 +02001217 / (double)fr.QuadPart) * 1000);
1218# else
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001219 if (now->tv_sec > due->tv_sec)
Bram Moolenaara8e93d62017-09-18 21:50:47 +02001220 return 0;
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001221 return (due->tv_sec - now->tv_sec) * 1000
1222 + (due->tv_usec - now->tv_usec) / 1000;
Bram Moolenaara8e93d62017-09-18 21:50:47 +02001223# endif
1224}
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001225
Bram Moolenaar975b5272016-03-15 23:10:59 +01001226/*
1227 * Insert a timer in the list of timers.
1228 */
1229 static void
1230insert_timer(timer_T *timer)
1231{
1232 timer->tr_next = first_timer;
1233 timer->tr_prev = NULL;
1234 if (first_timer != NULL)
1235 first_timer->tr_prev = timer;
1236 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +02001237 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001238}
1239
1240/*
1241 * Take a timer out of the list of timers.
1242 */
1243 static void
1244remove_timer(timer_T *timer)
1245{
1246 if (timer->tr_prev == NULL)
1247 first_timer = timer->tr_next;
1248 else
1249 timer->tr_prev->tr_next = timer->tr_next;
1250 if (timer->tr_next != NULL)
1251 timer->tr_next->tr_prev = timer->tr_prev;
1252}
1253
1254 static void
1255free_timer(timer_T *timer)
1256{
Bram Moolenaar75537a92016-09-05 22:45:28 +02001257 free_callback(timer->tr_callback, timer->tr_partial);
1258 vim_free(timer);
Bram Moolenaar975b5272016-03-15 23:10:59 +01001259}
1260
1261/*
1262 * Create a timer and return it. NULL if out of memory.
1263 * Caller should set the callback.
1264 */
1265 timer_T *
1266create_timer(long msec, int repeat)
1267{
1268 timer_T *timer = (timer_T *)alloc_clear(sizeof(timer_T));
Bram Moolenaaree39ef02016-09-10 19:17:42 +02001269 long prev_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001270
1271 if (timer == NULL)
1272 return NULL;
Bram Moolenaaree39ef02016-09-10 19:17:42 +02001273 if (++last_timer_id <= prev_id)
Bram Moolenaar75537a92016-09-05 22:45:28 +02001274 /* Overflow! Might cause duplicates... */
1275 last_timer_id = 0;
1276 timer->tr_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001277 insert_timer(timer);
1278 if (repeat != 0)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001279 timer->tr_repeat = repeat - 1;
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001280 timer->tr_interval = msec;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001281
1282 profile_setlimit(msec, &timer->tr_due);
1283 return timer;
1284}
1285
1286/*
1287 * Invoke the callback of "timer".
1288 */
1289 static void
1290timer_callback(timer_T *timer)
1291{
1292 typval_T rettv;
1293 int dummy;
1294 typval_T argv[2];
1295
1296 argv[0].v_type = VAR_NUMBER;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001297 argv[0].vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001298 argv[1].v_type = VAR_UNKNOWN;
1299
1300 call_func(timer->tr_callback, (int)STRLEN(timer->tr_callback),
Bram Moolenaardf48fb42016-07-22 21:50:18 +02001301 &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar975b5272016-03-15 23:10:59 +01001302 timer->tr_partial, NULL);
1303 clear_tv(&rettv);
1304}
1305
1306/*
1307 * Call timers that are due.
1308 * Return the time in msec until the next timer is due.
Bram Moolenaarc4f83382017-07-07 14:50:44 +02001309 * Returns -1 if there are no pending timers.
Bram Moolenaar975b5272016-03-15 23:10:59 +01001310 */
1311 long
Bram Moolenaarcf089462016-06-12 21:18:43 +02001312check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001313{
1314 timer_T *timer;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001315 timer_T *timer_next;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001316 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +01001317 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001318 proftime_T now;
1319 int did_one = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +02001320 int need_update_screen = FALSE;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001321 long current_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001322
Bram Moolenaarc577d812017-07-08 22:37:34 +02001323 /* Don't run any timers while exiting or dealing with an error. */
1324 if (exiting || aborting())
Bram Moolenaarc4f83382017-07-07 14:50:44 +02001325 return next_due;
1326
Bram Moolenaar75537a92016-09-05 22:45:28 +02001327 profile_start(&now);
1328 for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001329 {
Bram Moolenaar75537a92016-09-05 22:45:28 +02001330 timer_next = timer->tr_next;
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001331
Bram Moolenaar75537a92016-09-05 22:45:28 +02001332 if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
1333 continue;
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001334 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +02001335 if (this_due <= 1)
1336 {
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +02001337 /* Save and restore a lot of flags, because the timer fires while
1338 * waiting for a character, which might be halfway a command. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +02001339 int save_timer_busy = timer_busy;
1340 int save_vgetc_busy = vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +02001341 int save_did_emsg = did_emsg;
1342 int save_called_emsg = called_emsg;
Bram Moolenaar02e177d2017-08-26 23:43:28 +02001343 int save_must_redraw = must_redraw;
Bram Moolenaare723c422017-09-06 23:40:10 +02001344 int save_trylevel = trylevel;
1345 int save_did_throw = did_throw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +02001346 int save_ex_pressedreturn = get_pressedreturn();
Bram Moolenaare723c422017-09-06 23:40:10 +02001347 except_T *save_current_exception = current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +02001348 vimvars_save_T vvsave;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +02001349
Bram Moolenaare723c422017-09-06 23:40:10 +02001350 /* Create a scope for running the timer callback, ignoring most of
1351 * the current scope, such as being inside a try/catch. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +02001352 timer_busy = timer_busy > 0 || vgetc_busy > 0;
1353 vgetc_busy = 0;
Bram Moolenaarc577d812017-07-08 22:37:34 +02001354 called_emsg = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +02001355 did_emsg = FALSE;
1356 did_uncaught_emsg = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +02001357 must_redraw = 0;
Bram Moolenaare723c422017-09-06 23:40:10 +02001358 trylevel = 0;
1359 did_throw = FALSE;
1360 current_exception = NULL;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +02001361 save_vimvars(&vvsave);
Bram Moolenaar75537a92016-09-05 22:45:28 +02001362 timer->tr_firing = TRUE;
1363 timer_callback(timer);
1364 timer->tr_firing = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +02001365
Bram Moolenaar75537a92016-09-05 22:45:28 +02001366 timer_next = timer->tr_next;
1367 did_one = TRUE;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +02001368 timer_busy = save_timer_busy;
1369 vgetc_busy = save_vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +02001370 if (did_uncaught_emsg)
Bram Moolenaarc577d812017-07-08 22:37:34 +02001371 ++timer->tr_emsg_count;
Bram Moolenaare723c422017-09-06 23:40:10 +02001372 did_emsg = save_did_emsg;
1373 called_emsg = save_called_emsg;
1374 trylevel = save_trylevel;
1375 did_throw = save_did_throw;
1376 current_exception = save_current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +02001377 restore_vimvars(&vvsave);
Bram Moolenaar02e177d2017-08-26 23:43:28 +02001378 if (must_redraw != 0)
1379 need_update_screen = TRUE;
1380 must_redraw = must_redraw > save_must_redraw
1381 ? must_redraw : save_must_redraw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +02001382 set_pressedreturn(save_ex_pressedreturn);
Bram Moolenaar75537a92016-09-05 22:45:28 +02001383
1384 /* Only fire the timer again if it repeats and stop_timer() wasn't
1385 * called while inside the callback (tr_id == -1). */
Bram Moolenaarc577d812017-07-08 22:37:34 +02001386 if (timer->tr_repeat != 0 && timer->tr_id != -1
1387 && timer->tr_emsg_count < 3)
Bram Moolenaar75537a92016-09-05 22:45:28 +02001388 {
1389 profile_setlimit(timer->tr_interval, &timer->tr_due);
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001390 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +02001391 if (this_due < 1)
1392 this_due = 1;
1393 if (timer->tr_repeat > 0)
1394 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001395 }
Bram Moolenaar75537a92016-09-05 22:45:28 +02001396 else
1397 {
1398 this_due = -1;
1399 remove_timer(timer);
1400 free_timer(timer);
1401 }
Bram Moolenaar975b5272016-03-15 23:10:59 +01001402 }
Bram Moolenaar75537a92016-09-05 22:45:28 +02001403 if (this_due > 0 && (next_due == -1 || next_due > this_due))
1404 next_due = this_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001405 }
1406
1407 if (did_one)
Bram Moolenaar02e177d2017-08-26 23:43:28 +02001408 redraw_after_callback(need_update_screen);
Bram Moolenaar975b5272016-03-15 23:10:59 +01001409
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001410#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001411 if (bevalexpr_due_set)
1412 {
1413 this_due = proftime_time_left(&bevalexpr_due, &now);
1414 if (this_due <= 1)
1415 {
1416 bevalexpr_due_set = FALSE;
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001417 if (balloonEval == NULL)
1418 {
Bram Moolenaarca4b6132018-06-28 12:05:11 +02001419 balloonEval = (BalloonEval *)alloc_clear(sizeof(BalloonEval));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001420 balloonEvalForTerm = TRUE;
1421 }
1422 if (balloonEval != NULL)
1423 general_beval_cb(balloonEval, 0);
1424 }
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +02001425 else if (next_due == -1 || next_due > this_due)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001426 next_due = this_due;
1427 }
1428#endif
Bram Moolenaar56bc8e22018-05-10 18:05:56 +02001429#ifdef FEAT_TERMINAL
1430 /* Some terminal windows may need their buffer updated. */
1431 next_due = term_check_timers(next_due, &now);
1432#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001433
Bram Moolenaar75537a92016-09-05 22:45:28 +02001434 return current_id != last_timer_id ? 1 : next_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001435}
1436
1437/*
1438 * Find a timer by ID. Returns NULL if not found;
1439 */
1440 timer_T *
Bram Moolenaar75537a92016-09-05 22:45:28 +02001441find_timer(long id)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001442{
1443 timer_T *timer;
1444
Bram Moolenaar75537a92016-09-05 22:45:28 +02001445 if (id >= 0)
1446 {
1447 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1448 if (timer->tr_id == id)
1449 return timer;
1450 }
1451 return NULL;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001452}
1453
1454
1455/*
1456 * Stop a timer and delete it.
1457 */
1458 void
1459stop_timer(timer_T *timer)
1460{
Bram Moolenaar75537a92016-09-05 22:45:28 +02001461 if (timer->tr_firing)
1462 /* Free the timer after the callback returns. */
1463 timer->tr_id = -1;
1464 else
1465 {
1466 remove_timer(timer);
1467 free_timer(timer);
1468 }
Bram Moolenaar975b5272016-03-15 23:10:59 +01001469}
Bram Moolenaare3188e22016-05-31 21:13:04 +02001470
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001471 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001472stop_all_timers(void)
1473{
Bram Moolenaar75537a92016-09-05 22:45:28 +02001474 timer_T *timer;
1475 timer_T *timer_next;
1476
1477 for (timer = first_timer; timer != NULL; timer = timer_next)
1478 {
1479 timer_next = timer->tr_next;
1480 stop_timer(timer);
1481 }
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001482}
1483
1484 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001485add_timer_info(typval_T *rettv, timer_T *timer)
1486{
1487 list_T *list = rettv->vval.v_list;
1488 dict_T *dict = dict_alloc();
1489 dictitem_T *di;
1490 long remaining;
1491 proftime_T now;
1492
1493 if (dict == NULL)
1494 return;
1495 list_append_dict(list, dict);
1496
Bram Moolenaare0be1672018-07-08 16:50:37 +02001497 dict_add_number(dict, "id", timer->tr_id);
1498 dict_add_number(dict, "time", (long)timer->tr_interval);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001499
1500 profile_start(&now);
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001501 remaining = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaare0be1672018-07-08 16:50:37 +02001502 dict_add_number(dict, "remaining", (long)remaining);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001503
Bram Moolenaare0be1672018-07-08 16:50:37 +02001504 dict_add_number(dict, "repeat",
1505 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
1506 dict_add_number(dict, "paused", (long)(timer->tr_paused));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001507
1508 di = dictitem_alloc((char_u *)"callback");
1509 if (di != NULL)
1510 {
1511 if (dict_add(dict, di) == FAIL)
1512 vim_free(di);
1513 else if (timer->tr_partial != NULL)
1514 {
1515 di->di_tv.v_type = VAR_PARTIAL;
1516 di->di_tv.vval.v_partial = timer->tr_partial;
1517 ++timer->tr_partial->pt_refcount;
1518 }
1519 else
1520 {
1521 di->di_tv.v_type = VAR_FUNC;
1522 di->di_tv.vval.v_string = vim_strsave(timer->tr_callback);
1523 }
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001524 }
1525}
1526
1527 void
1528add_timer_info_all(typval_T *rettv)
1529{
1530 timer_T *timer;
1531
1532 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
Bram Moolenaar75537a92016-09-05 22:45:28 +02001533 if (timer->tr_id != -1)
1534 add_timer_info(rettv, timer);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001535}
1536
Bram Moolenaare3188e22016-05-31 21:13:04 +02001537/*
1538 * Mark references in partials of timers.
1539 */
1540 int
1541set_ref_in_timer(int copyID)
1542{
1543 int abort = FALSE;
1544 timer_T *timer;
1545 typval_T tv;
1546
1547 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1548 {
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +02001549 if (timer->tr_partial != NULL)
1550 {
1551 tv.v_type = VAR_PARTIAL;
1552 tv.vval.v_partial = timer->tr_partial;
1553 }
1554 else
1555 {
1556 tv.v_type = VAR_FUNC;
1557 tv.vval.v_string = timer->tr_callback;
1558 }
Bram Moolenaare3188e22016-05-31 21:13:04 +02001559 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
1560 }
1561 return abort;
1562}
Bram Moolenaar623e2632016-07-30 22:47:56 +02001563
1564# if defined(EXITFREE) || defined(PROTO)
1565 void
1566timer_free_all()
1567{
1568 timer_T *timer;
1569
1570 while (first_timer != NULL)
1571 {
1572 timer = first_timer;
1573 remove_timer(timer);
1574 free_timer(timer);
1575 }
1576}
1577# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +01001578# endif
1579
Bram Moolenaar113e1072019-01-20 15:30:40 +01001580#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT) && defined(FEAT_PROFILE)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001581# if defined(HAVE_MATH_H)
1582# include <math.h>
1583# endif
1584
1585/*
1586 * Divide the time "tm" by "count" and store in "tm2".
1587 */
1588 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001589profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001590{
1591 if (count == 0)
1592 profile_zero(tm2);
1593 else
1594 {
Bram Moolenaar4f974752019-02-17 17:44:42 +01001595# ifdef MSWIN
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001596 tm2->QuadPart = tm->QuadPart / count;
1597# else
1598 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1599
1600 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001601 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001602# endif
1603 }
1604}
1605#endif
1606
Bram Moolenaar76929292008-01-06 19:07:36 +00001607# if defined(FEAT_PROFILE) || defined(PROTO)
1608/*
1609 * Functions for profiling.
1610 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001611static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001612static proftime_T prof_wait_time;
1613
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001614/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001615 * Add the time "tm2" to "tm".
1616 */
1617 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001618profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001619{
Bram Moolenaar4f974752019-02-17 17:44:42 +01001620# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001621 tm->QuadPart += tm2->QuadPart;
1622# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001623 tm->tv_usec += tm2->tv_usec;
1624 tm->tv_sec += tm2->tv_sec;
1625 if (tm->tv_usec >= 1000000)
1626 {
1627 tm->tv_usec -= 1000000;
1628 ++tm->tv_sec;
1629 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001630# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001631}
1632
1633/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001634 * Add the "self" time from the total time and the children's time.
1635 */
1636 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001637profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001638{
1639 /* Check that the result won't be negative. Can happen with recursive
1640 * calls. */
Bram Moolenaar4f974752019-02-17 17:44:42 +01001641#ifdef MSWIN
Bram Moolenaar1056d982006-03-09 22:37:52 +00001642 if (total->QuadPart <= children->QuadPart)
1643 return;
1644#else
1645 if (total->tv_sec < children->tv_sec
1646 || (total->tv_sec == children->tv_sec
1647 && total->tv_usec <= children->tv_usec))
1648 return;
1649#endif
1650 profile_add(self, total);
1651 profile_sub(self, children);
1652}
1653
1654/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001655 * Get the current waittime.
1656 */
1657 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001658profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001659{
1660 *tm = prof_wait_time;
1661}
1662
1663/*
1664 * Subtract the passed waittime since "tm" from "tma".
1665 */
1666 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001667profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001668{
1669 proftime_T tm3 = prof_wait_time;
1670
1671 profile_sub(&tm3, tm);
1672 profile_sub(tma, &tm3);
1673}
1674
1675/*
1676 * Return TRUE if "tm1" and "tm2" are equal.
1677 */
1678 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001679profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001680{
Bram Moolenaar4f974752019-02-17 17:44:42 +01001681# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001682 return (tm1->QuadPart == tm2->QuadPart);
1683# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001684 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001685# endif
1686}
1687
1688/*
1689 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1690 */
1691 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001692profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001693{
Bram Moolenaar4f974752019-02-17 17:44:42 +01001694# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001695 return (int)(tm2->QuadPart - tm1->QuadPart);
1696# else
1697 if (tm1->tv_sec == tm2->tv_sec)
1698 return tm2->tv_usec - tm1->tv_usec;
1699 return tm2->tv_sec - tm1->tv_sec;
1700# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001701}
1702
Bram Moolenaar05159a02005-02-26 23:04:13 +00001703static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001704static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001705
1706/*
1707 * ":profile cmd args"
1708 */
1709 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001710ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001711{
1712 char_u *e;
1713 int len;
1714
1715 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001716 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001717 e = skipwhite(e);
1718
1719 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1720 {
1721 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001722 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001723 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001724 profile_zero(&prof_wait_time);
1725 set_vim_var_nr(VV_PROFILING, 1L);
1726 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001727 else if (do_profiling == PROF_NONE)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001728 emsg(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001729 else if (STRCMP(eap->arg, "pause") == 0)
1730 {
1731 if (do_profiling == PROF_YES)
1732 profile_start(&pause_time);
1733 do_profiling = PROF_PAUSED;
1734 }
1735 else if (STRCMP(eap->arg, "continue") == 0)
1736 {
1737 if (do_profiling == PROF_PAUSED)
1738 {
1739 profile_end(&pause_time);
1740 profile_add(&prof_wait_time, &pause_time);
1741 }
1742 do_profiling = PROF_YES;
1743 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001744 else
1745 {
1746 /* The rest is similar to ":breakadd". */
1747 ex_breakadd(eap);
1748 }
1749}
1750
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001751/* Command line expansion for :profile. */
1752static enum
1753{
1754 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001755 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001756} pexpand_what;
1757
1758static char *pexpand_cmds[] = {
1759 "start",
1760#define PROFCMD_START 0
1761 "pause",
1762#define PROFCMD_PAUSE 1
1763 "continue",
1764#define PROFCMD_CONTINUE 2
1765 "func",
1766#define PROFCMD_FUNC 3
1767 "file",
1768#define PROFCMD_FILE 4
1769 NULL
1770#define PROFCMD_LAST 5
1771};
1772
1773/*
1774 * Function given to ExpandGeneric() to obtain the profile command
1775 * specific expansion.
1776 */
1777 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001778get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001779{
1780 switch (pexpand_what)
1781 {
1782 case PEXP_SUBCMD:
1783 return (char_u *)pexpand_cmds[idx];
1784 /* case PEXP_FUNC: TODO */
1785 default:
1786 return NULL;
1787 }
1788}
1789
1790/*
1791 * Handle command line completion for :profile command.
1792 */
1793 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001794set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001795{
1796 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001797
1798 /* Default: expand subcommands. */
1799 xp->xp_context = EXPAND_PROFILE;
1800 pexpand_what = PEXP_SUBCMD;
1801 xp->xp_pattern = arg;
1802
1803 end_subcmd = skiptowhite(arg);
1804 if (*end_subcmd == NUL)
1805 return;
1806
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001807 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001808 {
1809 xp->xp_context = EXPAND_FILES;
1810 xp->xp_pattern = skipwhite(end_subcmd);
1811 return;
1812 }
1813
1814 /* TODO: expand function names after "func" */
1815 xp->xp_context = EXPAND_NOTHING;
1816}
1817
Bram Moolenaar05159a02005-02-26 23:04:13 +00001818/*
1819 * Dump the profiling info.
1820 */
1821 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001822profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001823{
1824 FILE *fd;
1825
1826 if (profile_fname != NULL)
1827 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001828 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001829 if (fd == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001830 semsg(_(e_notopen), profile_fname);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001831 else
1832 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001833 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001834 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001835 fclose(fd);
1836 }
1837 }
1838}
1839
1840/*
1841 * Start profiling script "fp".
1842 */
1843 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001844script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001845{
1846 si->sn_pr_count = 0;
1847 profile_zero(&si->sn_pr_total);
1848 profile_zero(&si->sn_pr_self);
1849
1850 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1851 si->sn_prl_idx = -1;
1852 si->sn_prof_on = TRUE;
1853 si->sn_pr_nest = 0;
1854}
1855
1856/*
Bram Moolenaar67435d92017-10-19 21:04:37 +02001857 * Save time when starting to invoke another script or function.
Bram Moolenaar05159a02005-02-26 23:04:13 +00001858 */
1859 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001860script_prof_save(
1861 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001862{
1863 scriptitem_T *si;
1864
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02001865 if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001866 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02001867 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001868 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1869 profile_start(&si->sn_pr_child);
1870 }
1871 profile_get_wait(tm);
1872}
1873
1874/*
1875 * Count time spent in children after invoking another script or function.
1876 */
1877 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001878script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001879{
1880 scriptitem_T *si;
1881
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02001882 if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001883 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02001884 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001885 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1886 {
1887 profile_end(&si->sn_pr_child);
1888 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1889 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1890 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1891 }
1892 }
1893}
1894
1895static proftime_T inchar_time;
1896
1897/*
1898 * Called when starting to wait for the user to type a character.
1899 */
1900 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001901prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001902{
1903 profile_start(&inchar_time);
1904}
1905
1906/*
1907 * Called when finished waiting for the user to type a character.
1908 */
1909 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001910prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001911{
1912 profile_end(&inchar_time);
1913 profile_add(&prof_wait_time, &inchar_time);
1914}
1915
1916/*
1917 * Dump the profiling results for all scripts in file "fd".
1918 */
1919 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001920script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001921{
1922 int id;
1923 scriptitem_T *si;
1924 int i;
1925 FILE *sfd;
1926 sn_prl_T *pp;
1927
1928 for (id = 1; id <= script_items.ga_len; ++id)
1929 {
1930 si = &SCRIPT_ITEM(id);
1931 if (si->sn_prof_on)
1932 {
1933 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1934 if (si->sn_pr_count == 1)
1935 fprintf(fd, "Sourced 1 time\n");
1936 else
1937 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1938 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1939 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1940 fprintf(fd, "\n");
1941 fprintf(fd, "count total (s) self (s)\n");
1942
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001943 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001944 if (sfd == NULL)
1945 fprintf(fd, "Cannot open file!\n");
1946 else
1947 {
Bram Moolenaar67435d92017-10-19 21:04:37 +02001948 /* Keep going till the end of file, so that trailing
1949 * continuation lines are listed. */
1950 for (i = 0; ; ++i)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001951 {
1952 if (vim_fgets(IObuff, IOSIZE, sfd))
1953 break;
Bram Moolenaarac112f02017-12-05 16:46:28 +01001954 /* When a line has been truncated, append NL, taking care
1955 * of multi-byte characters . */
1956 if (IObuff[IOSIZE - 2] != NUL && IObuff[IOSIZE - 2] != NL)
1957 {
1958 int n = IOSIZE - 2;
Bram Moolenaar13505972019-01-24 15:04:48 +01001959
Bram Moolenaarac112f02017-12-05 16:46:28 +01001960 if (enc_utf8)
1961 {
1962 /* Move to the first byte of this char.
1963 * utf_head_off() doesn't work, because it checks
1964 * for a truncated character. */
1965 while (n > 0 && (IObuff[n] & 0xc0) == 0x80)
1966 --n;
1967 }
1968 else if (has_mbyte)
1969 n -= mb_head_off(IObuff, IObuff + n);
Bram Moolenaarac112f02017-12-05 16:46:28 +01001970 IObuff[n] = NL;
1971 IObuff[n + 1] = NUL;
1972 }
Bram Moolenaar67435d92017-10-19 21:04:37 +02001973 if (i < si->sn_prl_ga.ga_len
1974 && (pp = &PRL_ITEM(si, i))->snp_count > 0)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001975 {
1976 fprintf(fd, "%5d ", pp->snp_count);
1977 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1978 fprintf(fd, " ");
1979 else
1980 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1981 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1982 }
1983 else
1984 fprintf(fd, " ");
1985 fprintf(fd, "%s", IObuff);
1986 }
1987 fclose(sfd);
1988 }
1989 fprintf(fd, "\n");
1990 }
1991 }
1992}
1993
1994/*
1995 * Return TRUE when a function defined in the current script should be
1996 * profiled.
1997 */
1998 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001999prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002000{
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002001 if (current_sctx.sc_sid > 0)
2002 return SCRIPT_ITEM(current_sctx.sc_sid).sn_pr_force;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00002003 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002004}
2005
2006# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002007#endif
2008
2009/*
2010 * If 'autowrite' option set, try to write the file.
2011 * Careful: autocommands may make "buf" invalid!
2012 *
2013 * return FAIL for failure, OK otherwise
2014 */
2015 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002016autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002017{
Bram Moolenaar373154b2007-02-13 05:19:30 +00002018 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002019 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00002020
Bram Moolenaar071d4272004-06-13 20:20:40 +00002021 if (!(p_aw || p_awa) || !p_write
2022#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00002023 /* never autowrite a "nofile" or "nowrite" buffer */
2024 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002025#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00002026 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002027 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002028 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00002029 r = buf_write_all(buf, forceit);
2030
2031 /* Writing may succeed but the buffer still changed, e.g., when there is a
2032 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002033 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00002034 r = FAIL;
2035 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002036}
2037
2038/*
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +02002039 * Flush all buffers, except the ones that are readonly or are never written.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002040 */
2041 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002042autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043{
2044 buf_T *buf;
2045
2046 if (!(p_aw || p_awa) || !p_write)
2047 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02002048 FOR_ALL_BUFFERS(buf)
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +02002049 if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002050 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002051 bufref_T bufref;
2052
2053 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002054
Bram Moolenaar071d4272004-06-13 20:20:40 +00002055 (void)buf_write_all(buf, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002056
Bram Moolenaar071d4272004-06-13 20:20:40 +00002057 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002058 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002059 buf = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060 }
2061}
2062
2063/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002064 * Return TRUE if buffer was changed and cannot be abandoned.
2065 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002066 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002067 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002068check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002069{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002070 int forceit = (flags & CCGD_FORCEIT);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002071 bufref_T bufref;
2072
2073 set_bufref(&bufref, buf);
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002074
Bram Moolenaar071d4272004-06-13 20:20:40 +00002075 if ( !forceit
2076 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002077 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
2078 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002079 {
2080#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2081 if ((p_confirm || cmdmod.confirm) && p_write)
2082 {
2083 buf_T *buf2;
2084 int count = 0;
2085
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002086 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02002087 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088 if (bufIsChanged(buf2)
2089 && (buf2->b_ffname != NULL
2090# ifdef FEAT_BROWSE
2091 || cmdmod.browse
2092# endif
2093 ))
2094 ++count;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002095 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002096 /* Autocommand deleted buffer, oops! It's not changed now. */
2097 return FALSE;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002098
Bram Moolenaar071d4272004-06-13 20:20:40 +00002099 dialog_changed(buf, count > 1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002100
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002101 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002102 /* Autocommand deleted buffer, oops! It's not changed now. */
2103 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002104 return bufIsChanged(buf);
2105 }
2106#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002107 if (flags & CCGD_EXCMD)
Bram Moolenaarf5be7cd2017-08-17 16:55:13 +02002108 no_write_message();
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002109 else
Bram Moolenaar7a760922018-02-19 23:10:02 +01002110 no_write_message_nobang(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002111 return TRUE;
2112 }
2113 return FALSE;
2114}
2115
2116#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
2117
2118#if defined(FEAT_BROWSE) || defined(PROTO)
2119/*
2120 * When wanting to write a file without a file name, ask the user for a name.
2121 */
2122 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002123browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124{
2125 if (buf->b_fname == NULL)
2126 {
2127 char_u *fname;
2128
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002129 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
2130 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002131 if (fname != NULL)
2132 {
2133 if (setfname(buf, fname, NULL, TRUE) == OK)
2134 buf->b_flags |= BF_NOTEDITED;
2135 vim_free(fname);
2136 }
2137 }
2138}
2139#endif
2140
2141/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02002142 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002143 * Must check 'write' option first!
2144 */
2145 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002146dialog_changed(
2147 buf_T *buf,
2148 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002149{
Bram Moolenaard9462e32011-04-11 21:35:11 +02002150 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002151 int ret;
2152 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02002153 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002154
Bram Moolenaar3f9a1ff2017-08-21 22:06:02 +02002155 dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002156 if (checkall)
2157 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
2158 else
2159 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
2160
Bram Moolenaar8218f602012-04-25 17:32:18 +02002161 /* Init ea pseudo-structure, this is needed for the check_overwrite()
2162 * function. */
2163 ea.append = ea.forceit = FALSE;
2164
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165 if (ret == VIM_YES)
2166 {
2167#ifdef FEAT_BROWSE
2168 /* May get file name, when there is none */
2169 browse_save_fname(buf);
2170#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02002171 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
2172 buf->b_fname, buf->b_ffname, FALSE) == OK)
2173 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002174 (void)buf_write_all(buf, FALSE);
2175 }
2176 else if (ret == VIM_NO)
2177 {
2178 unchanged(buf, TRUE);
2179 }
2180 else if (ret == VIM_ALL)
2181 {
2182 /*
2183 * Write all modified files that can be written.
2184 * Skip readonly buffers, these need to be confirmed
2185 * individually.
2186 */
Bram Moolenaar29323592016-07-24 22:04:11 +02002187 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002188 {
2189 if (bufIsChanged(buf2)
2190 && (buf2->b_ffname != NULL
2191#ifdef FEAT_BROWSE
2192 || cmdmod.browse
2193#endif
2194 )
2195 && !buf2->b_p_ro)
2196 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002197 bufref_T bufref;
2198
2199 set_bufref(&bufref, buf2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200#ifdef FEAT_BROWSE
2201 /* May get file name, when there is none */
2202 browse_save_fname(buf2);
2203#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02002204 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
2205 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
2206 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002207 (void)buf_write_all(buf2, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002208
Bram Moolenaar071d4272004-06-13 20:20:40 +00002209 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002210 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002211 buf2 = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002212 }
2213 }
2214 }
2215 else if (ret == VIM_DISCARDALL)
2216 {
2217 /*
2218 * mark all buffers as unchanged
2219 */
Bram Moolenaar29323592016-07-24 22:04:11 +02002220 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002221 unchanged(buf2, TRUE);
2222 }
2223}
2224#endif
2225
2226/*
2227 * Return TRUE if the buffer "buf" can be abandoned, either by making it
2228 * hidden, autowriting it or unloading it.
2229 */
2230 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002231can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002232{
Bram Moolenaareb44a682017-08-03 22:44:55 +02002233 return ( buf_hide(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002234 || !bufIsChanged(buf)
2235 || buf->b_nwindows > 1
2236 || autowrite(buf, forceit) == OK
2237 || forceit);
2238}
2239
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002240/*
2241 * Add a buffer number to "bufnrs", unless it's already there.
2242 */
2243 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002244add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002245{
2246 int i;
2247
2248 for (i = 0; i < *bufnump; ++i)
2249 if (bufnrs[i] == nr)
2250 return;
2251 bufnrs[*bufnump] = nr;
2252 *bufnump = *bufnump + 1;
2253}
2254
Bram Moolenaar071d4272004-06-13 20:20:40 +00002255/*
2256 * Return TRUE if any buffer was changed and cannot be abandoned.
2257 * That changed buffer becomes the current buffer.
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01002258 * When "unload" is TRUE the current buffer is unloaded instead of making it
Bram Moolenaar027387f2016-01-02 22:25:52 +01002259 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002260 */
2261 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002262check_changed_any(
2263 int hidden, /* Only check hidden buffers */
2264 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002266 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267 buf_T *buf;
2268 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002269 int i;
2270 int bufnum = 0;
2271 int bufcount = 0;
2272 int *bufnrs;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002273 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002275
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01002276 /* Make a list of all buffers, with the most important ones first. */
Bram Moolenaar29323592016-07-24 22:04:11 +02002277 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002278 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002280 if (bufcount == 0)
2281 return FALSE;
2282
2283 bufnrs = (int *)alloc(sizeof(int) * bufcount);
2284 if (bufnrs == NULL)
2285 return FALSE;
2286
2287 /* curbuf */
2288 bufnrs[bufnum++] = curbuf->b_fnum;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01002289
2290 /* buffers in current tab */
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002291 FOR_ALL_WINDOWS(wp)
2292 if (wp->w_buffer != curbuf)
2293 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2294
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01002295 /* buffers in other tabs */
Bram Moolenaar29323592016-07-24 22:04:11 +02002296 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002297 if (tp != curtab)
2298 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
2299 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01002300
2301 /* any other buffer */
Bram Moolenaar29323592016-07-24 22:04:11 +02002302 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002303 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
2304
2305 for (i = 0; i < bufnum; ++i)
2306 {
2307 buf = buflist_findnr(bufnrs[i]);
2308 if (buf == NULL)
2309 continue;
2310 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
2311 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002312 bufref_T bufref;
2313
2314 set_bufref(&bufref, buf);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01002315#ifdef FEAT_TERMINAL
2316 if (term_job_running(buf->b_term))
2317 {
2318 if (term_try_stop_job(buf) == FAIL)
2319 break;
2320 }
2321 else
2322#endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002323 /* Try auto-writing the buffer. If this fails but the buffer no
2324 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002325 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
2326 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002327 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002328 break; /* didn't save - still changes */
2329 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002330 }
2331
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002332 if (i >= bufnum)
2333 goto theend;
2334
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01002335 /* Get here if "buf" cannot be abandoned. */
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002336 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002337 exiting = FALSE;
2338#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2339 /*
2340 * When ":confirm" used, don't give an error message.
2341 */
2342 if (!(p_confirm || cmdmod.confirm))
2343#endif
2344 {
2345 /* There must be a wait_return for this message, do_buffer()
2346 * may cause a redraw. But wait_return() is a no-op when vgetc()
2347 * is busy (Quit used from window menu), then make sure we don't
2348 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00002349 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350 {
2351 msg_row = cmdline_row;
2352 msg_col = 0;
2353 msg_didout = FALSE;
2354 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02002355 if (
2356#ifdef FEAT_TERMINAL
2357 term_job_running(buf->b_term)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002358 ? semsg(_("E947: Job still running in buffer \"%s\""),
Bram Moolenaareb44a682017-08-03 22:44:55 +02002359 buf->b_fname)
2360 :
2361#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002362 semsg(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02002363 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364 {
2365 save = no_wait_return;
2366 no_wait_return = FALSE;
2367 wait_return(FALSE);
2368 no_wait_return = save;
2369 }
2370 }
2371
Bram Moolenaar071d4272004-06-13 20:20:40 +00002372 /* Try to find a window that contains the buffer. */
2373 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002374 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375 if (wp->w_buffer == buf)
2376 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002377 bufref_T bufref;
2378
2379 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002380
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002381 goto_tabpage_win(tp, wp);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002382
Bram Moolenaar071d4272004-06-13 20:20:40 +00002383 /* Paranoia: did autocms wipe out the buffer with changes? */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002384 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002385 goto theend;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002386 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002387 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002388buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002389
2390 /* Open the changed buffer in the current window. */
2391 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01002392 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002393
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002394theend:
2395 vim_free(bufnrs);
2396 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002397}
2398
2399/*
2400 * return FAIL if there is no file name, OK if there is one
2401 * give error message for FAIL
2402 */
2403 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002404check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405{
2406 if (curbuf->b_ffname == NULL)
2407 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002408 emsg(_(e_noname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409 return FAIL;
2410 }
2411 return OK;
2412}
2413
2414/*
2415 * flush the contents of a buffer, unless it has no file name
2416 *
2417 * return FAIL for failure, OK otherwise
2418 */
2419 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002420buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002421{
2422 int retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002423 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002424
2425 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
2426 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
2427 FALSE, forceit, TRUE, FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002428 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002429 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01002430 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +01002431 msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002432 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433 return retval;
2434}
2435
2436/*
2437 * Code to handle the argument list.
2438 */
2439
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002440static int do_arglist(char_u *str, int what, int after, int will_edit);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002441static void alist_check_arg_idx(void);
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002442static void alist_add_list(int count, char_u **files, int after, int will_edit);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002443#define AL_SET 1
2444#define AL_ADD 2
2445#define AL_DEL 3
2446
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002448 * Isolate one argument, taking backticks.
2449 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002450 * Return a pointer to the start of the next argument.
2451 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002452 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002453do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454{
2455 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456 int inbacktick;
2457
Bram Moolenaar071d4272004-06-13 20:20:40 +00002458 inbacktick = FALSE;
2459 for (p = str; *str; ++str)
2460 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002461 /* When the backslash is used for escaping the special meaning of a
2462 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463 if (rem_backslash(str))
2464 {
2465 *p++ = *str++;
2466 *p++ = *str;
2467 }
2468 else
2469 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002470 /* An item ends at a space not in backticks */
2471 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002472 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002473 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002475 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002476 }
2477 }
2478 str = skipwhite(str);
2479 *p = NUL;
2480
2481 return str;
2482}
2483
Bram Moolenaar86b68352004-12-27 21:59:20 +00002484/*
2485 * Separate the arguments in "str" and return a list of pointers in the
2486 * growarray "gap".
2487 */
Bram Moolenaar398ee732017-08-03 14:29:14 +02002488 static int
2489get_arglist(garray_T *gap, char_u *str, int escaped)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002490{
2491 ga_init2(gap, (int)sizeof(char_u *), 20);
2492 while (*str != NUL)
2493 {
2494 if (ga_grow(gap, 1) == FAIL)
2495 {
2496 ga_clear(gap);
2497 return FAIL;
2498 }
2499 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2500
Bram Moolenaar398ee732017-08-03 14:29:14 +02002501 /* If str is escaped, don't handle backslashes or spaces */
2502 if (!escaped)
2503 return OK;
2504
Bram Moolenaar86b68352004-12-27 21:59:20 +00002505 /* Isolate one argument, change it in-place, put a NUL after it. */
2506 str = do_one_arg(str);
2507 }
2508 return OK;
2509}
2510
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002511#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002512/*
2513 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002514 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002515 * Return FAIL or OK.
2516 */
2517 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002518get_arglist_exp(
2519 char_u *str,
2520 int *fcountp,
2521 char_u ***fnamesp,
2522 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002523{
2524 garray_T ga;
2525 int i;
2526
Bram Moolenaar398ee732017-08-03 14:29:14 +02002527 if (get_arglist(&ga, str, TRUE) == FAIL)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002528 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002529 if (wig == TRUE)
2530 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2531 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2532 else
2533 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2534 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2535
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002536 ga_clear(&ga);
2537 return i;
2538}
2539#endif
2540
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541/*
2542 * Redefine the argument list.
2543 */
2544 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002545set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002546{
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002547 do_arglist(str, AL_SET, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002549
2550/*
2551 * "what" == AL_SET: Redefine the argument list to 'str'.
2552 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2553 * "what" == AL_DEL: remove files in 'str' from the argument list.
2554 *
2555 * Return FAIL for failure, OK otherwise.
2556 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002558do_arglist(
2559 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01002560 int what,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002561 int after UNUSED, // 0 means before first one
2562 int will_edit) // will edit added argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00002563{
2564 garray_T new_ga;
2565 int exp_count;
2566 char_u **exp_files;
2567 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002568 char_u *p;
2569 int match;
Bram Moolenaar398ee732017-08-03 14:29:14 +02002570 int arg_escaped = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571
2572 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002573 * Set default argument for ":argadd" command.
2574 */
2575 if (what == AL_ADD && *str == NUL)
2576 {
2577 if (curbuf->b_ffname == NULL)
2578 return FAIL;
2579 str = curbuf->b_fname;
Bram Moolenaar398ee732017-08-03 14:29:14 +02002580 arg_escaped = FALSE;
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002581 }
2582
2583 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584 * Collect all file name arguments in "new_ga".
2585 */
Bram Moolenaar398ee732017-08-03 14:29:14 +02002586 if (get_arglist(&new_ga, str, arg_escaped) == FAIL)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002587 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002588
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589 if (what == AL_DEL)
2590 {
2591 regmatch_T regmatch;
2592 int didone;
2593
2594 /*
2595 * Delete the items: use each item as a regexp and find a match in the
2596 * argument list.
2597 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002598 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002599 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2600 {
2601 p = ((char_u **)new_ga.ga_data)[i];
2602 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2603 if (p == NULL)
2604 break;
2605 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2606 if (regmatch.regprog == NULL)
2607 {
2608 vim_free(p);
2609 break;
2610 }
2611
2612 didone = FALSE;
2613 for (match = 0; match < ARGCOUNT; ++match)
2614 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2615 (colnr_T)0))
2616 {
2617 didone = TRUE;
2618 vim_free(ARGLIST[match].ae_fname);
2619 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2620 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2621 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002622 if (curwin->w_arg_idx > match)
2623 --curwin->w_arg_idx;
2624 --match;
2625 }
2626
Bram Moolenaar473de612013-06-08 18:19:48 +02002627 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628 vim_free(p);
2629 if (!didone)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002630 semsg(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002631 }
2632 ga_clear(&new_ga);
2633 }
2634 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002635 {
2636 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2637 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2638 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002639 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002640 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002641 emsg(_(e_nomatch));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002642 return FAIL;
2643 }
2644
Bram Moolenaar071d4272004-06-13 20:20:40 +00002645 if (what == AL_ADD)
2646 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002647 alist_add_list(exp_count, exp_files, after, will_edit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002648 vim_free(exp_files);
2649 }
2650 else /* what == AL_SET */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002651 alist_set(ALIST(curwin), exp_count, exp_files, will_edit, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652 }
2653
2654 alist_check_arg_idx();
2655
2656 return OK;
2657}
2658
2659/*
2660 * Check the validity of the arg_idx for each other window.
2661 */
2662 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002663alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002664{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002665 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002666 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667
Bram Moolenaarf740b292006-02-16 22:11:02 +00002668 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002669 if (win->w_alist == curwin->w_alist)
2670 check_arg_idx(win);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002671}
2672
2673/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002674 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002675 * index.
2676 */
2677 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002678editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002679{
2680 return !(win->w_arg_idx >= WARGCOUNT(win)
2681 || (win->w_buffer->b_fnum
2682 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2683 && (win->w_buffer->b_ffname == NULL
2684 || !(fullpathcmp(
2685 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2686 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2687}
2688
2689/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002690 * Check if window "win" is editing the w_arg_idx file in its argument list.
2691 */
2692 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002693check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002694{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002695 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002696 {
2697 /* We are not editing the current entry in the argument list.
2698 * Set "arg_had_last" if we are editing the last one. */
2699 win->w_arg_idx_invalid = TRUE;
2700 if (win->w_arg_idx != WARGCOUNT(win) - 1
2701 && arg_had_last == FALSE
Bram Moolenaar071d4272004-06-13 20:20:40 +00002702 && ALIST(win) == &global_alist
Bram Moolenaar071d4272004-06-13 20:20:40 +00002703 && GARGCOUNT > 0
2704 && win->w_arg_idx < GARGCOUNT
2705 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2706 || (win->w_buffer->b_ffname != NULL
2707 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2708 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2709 arg_had_last = TRUE;
2710 }
2711 else
2712 {
2713 /* We are editing the current entry in the argument list.
2714 * Set "arg_had_last" if it's also the last one */
2715 win->w_arg_idx_invalid = FALSE;
2716 if (win->w_arg_idx == WARGCOUNT(win) - 1
Bram Moolenaar4033c552017-09-16 20:54:51 +02002717 && win->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718 arg_had_last = TRUE;
2719 }
2720}
2721
2722/*
2723 * ":args", ":argslocal" and ":argsglobal".
2724 */
2725 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002726ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002727{
2728 int i;
2729
2730 if (eap->cmdidx != CMD_args)
2731 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002732 alist_unlink(ALIST(curwin));
2733 if (eap->cmdidx == CMD_argglobal)
2734 ALIST(curwin) = &global_alist;
2735 else /* eap->cmdidx == CMD_arglocal */
2736 alist_new();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002737 }
2738
Bram Moolenaar2ac372c2018-12-28 19:06:47 +01002739 if (*eap->arg != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002740 {
2741 /*
2742 * ":args file ..": define new argument list, handle like ":next"
2743 * Also for ":argslocal file .." and ":argsglobal file ..".
2744 */
2745 ex_next(eap);
2746 }
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02002747 else if (eap->cmdidx == CMD_args)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002748 {
2749 /*
2750 * ":args": list arguments.
2751 */
2752 if (ARGCOUNT > 0)
2753 {
Bram Moolenaar405dadb2018-04-20 22:48:58 +02002754 char_u **items = (char_u **)alloc(sizeof(char_u *) * ARGCOUNT);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02002755
2756 if (items != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757 {
Bram Moolenaar5d69da42018-04-20 22:01:41 +02002758 /* Overwrite the command, for a short list there is no
2759 * scrolling required and no wait_return(). */
2760 gotocmdline(TRUE);
2761
2762 for (i = 0; i < ARGCOUNT; ++i)
Bram Moolenaar405dadb2018-04-20 22:48:58 +02002763 items[i] = alist_name(&ARGLIST[i]);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02002764 list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
2765 vim_free(items);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002766 }
2767 }
2768 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769 else if (eap->cmdidx == CMD_arglocal)
2770 {
2771 garray_T *gap = &curwin->w_alist->al_ga;
2772
2773 /*
2774 * ":argslocal": make a local copy of the global argument list.
2775 */
2776 if (ga_grow(gap, GARGCOUNT) == OK)
2777 for (i = 0; i < GARGCOUNT; ++i)
2778 if (GARGLIST[i].ae_fname != NULL)
2779 {
2780 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2781 vim_strsave(GARGLIST[i].ae_fname);
2782 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2783 GARGLIST[i].ae_fnum;
2784 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785 }
2786 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002787}
2788
2789/*
2790 * ":previous", ":sprevious", ":Next" and ":sNext".
2791 */
2792 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002793ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002794{
2795 /* If past the last one already, go to the last one. */
2796 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2797 do_argfile(eap, ARGCOUNT - 1);
2798 else
2799 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2800}
2801
2802/*
2803 * ":rewind", ":first", ":sfirst" and ":srewind".
2804 */
2805 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002806ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002807{
2808 do_argfile(eap, 0);
2809}
2810
2811/*
2812 * ":last" and ":slast".
2813 */
2814 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002815ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002816{
2817 do_argfile(eap, ARGCOUNT - 1);
2818}
2819
2820/*
2821 * ":argument" and ":sargument".
2822 */
2823 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002824ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002825{
2826 int i;
2827
2828 if (eap->addr_count > 0)
2829 i = eap->line2 - 1;
2830 else
2831 i = curwin->w_arg_idx;
2832 do_argfile(eap, i);
2833}
2834
2835/*
2836 * Edit file "argn" of the argument lists.
2837 */
2838 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002839do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002840{
2841 int other;
2842 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002843 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002844
2845 if (argn < 0 || argn >= ARGCOUNT)
2846 {
2847 if (ARGCOUNT <= 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002848 emsg(_("E163: There is only one file to edit"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002849 else if (argn < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002850 emsg(_("E164: Cannot go before first file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002852 emsg(_("E165: Cannot go beyond last file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002853 }
2854 else
2855 {
2856 setpcmark();
2857#ifdef FEAT_GUI
2858 need_mouse_correct = TRUE;
2859#endif
2860
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002861 /* split window or create new tab page first */
2862 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002863 {
2864 if (win_split(0, 0) == FAIL)
2865 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002866 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002867 }
2868 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002869 {
2870 /*
2871 * if 'hidden' set, only check for changed file when re-editing
2872 * the same buffer
2873 */
2874 other = TRUE;
Bram Moolenaareb44a682017-08-03 22:44:55 +02002875 if (buf_hide(curbuf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002876 {
2877 p = fix_fname(alist_name(&ARGLIST[argn]));
2878 other = otherfile(p);
2879 vim_free(p);
2880 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02002881 if ((!buf_hide(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002882 && check_changed(curbuf, CCGD_AW
2883 | (other ? 0 : CCGD_MULTWIN)
2884 | (eap->forceit ? CCGD_FORCEIT : 0)
2885 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002886 return;
2887 }
2888
2889 curwin->w_arg_idx = argn;
Bram Moolenaar4033c552017-09-16 20:54:51 +02002890 if (argn == ARGCOUNT - 1 && curwin->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002891 arg_had_last = TRUE;
2892
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002893 /* Edit the file; always use the last known line number.
2894 * When it fails (e.g. Abort for already edited file) restore the
2895 * argument index. */
2896 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897 eap, ECMD_LAST,
Bram Moolenaareb44a682017-08-03 22:44:55 +02002898 (buf_hide(curwin->w_buffer) ? ECMD_HIDE : 0)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002899 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002900 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002901 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002902 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002903 setmark('\'');
2904 }
2905}
2906
2907/*
2908 * ":next", and commands that behave like it.
2909 */
2910 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002911ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912{
2913 int i;
2914
2915 /*
2916 * check for changed buffer now, if this fails the argument list is not
2917 * redefined.
2918 */
Bram Moolenaareb44a682017-08-03 22:44:55 +02002919 if ( buf_hide(curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002920 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002921 || !check_changed(curbuf, CCGD_AW
2922 | (eap->forceit ? CCGD_FORCEIT : 0)
2923 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924 {
2925 if (*eap->arg != NUL) /* redefine file list */
2926 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002927 if (do_arglist(eap->arg, AL_SET, 0, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928 return;
2929 i = 0;
2930 }
2931 else
2932 i = curwin->w_arg_idx + (int)eap->line2;
2933 do_argfile(eap, i);
2934 }
2935}
2936
Bram Moolenaar071d4272004-06-13 20:20:40 +00002937/*
2938 * ":argedit"
2939 */
2940 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002941ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942{
Bram Moolenaar90305c62017-07-16 15:31:17 +02002943 int i = eap->addr_count ? (int)eap->line2 : curwin->w_arg_idx + 1;
Bram Moolenaar46a53df2018-04-24 21:58:51 +02002944 // Whether curbuf will be reused, curbuf->b_ffname will be set.
2945 int curbuf_is_reusable = curbuf_reusable();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002947 if (do_arglist(eap->arg, AL_ADD, i, TRUE) == FAIL)
Bram Moolenaar90305c62017-07-16 15:31:17 +02002948 return;
2949#ifdef FEAT_TITLE
2950 maketitle();
2951#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952
Bram Moolenaar46a53df2018-04-24 21:58:51 +02002953 if (curwin->w_arg_idx == 0
2954 && (curbuf->b_ml.ml_flags & ML_EMPTY)
2955 && (curbuf->b_ffname == NULL || curbuf_is_reusable))
Bram Moolenaar90305c62017-07-16 15:31:17 +02002956 i = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002957 /* Edit the argument. */
Bram Moolenaar90305c62017-07-16 15:31:17 +02002958 if (i < ARGCOUNT)
2959 do_argfile(eap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002960}
2961
2962/*
2963 * ":argadd"
2964 */
2965 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002966ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967{
2968 do_arglist(eap->arg, AL_ADD,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002969 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1,
2970 FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971#ifdef FEAT_TITLE
2972 maketitle();
2973#endif
2974}
2975
2976/*
2977 * ":argdelete"
2978 */
2979 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002980ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002981{
2982 int i;
2983 int n;
2984
2985 if (eap->addr_count > 0)
2986 {
2987 /* ":1,4argdel": Delete all arguments in the range. */
2988 if (eap->line2 > ARGCOUNT)
2989 eap->line2 = ARGCOUNT;
2990 n = eap->line2 - eap->line1 + 1;
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002991 if (*eap->arg != NUL)
2992 /* Can't have both a range and an argument. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002993 emsg(_(e_invarg));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002994 else if (n <= 0)
2995 {
2996 /* Don't give an error for ":%argdel" if the list is empty. */
2997 if (eap->line1 != 1 || eap->line2 != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002998 emsg(_(e_invrange));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002999 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000 else
3001 {
3002 for (i = eap->line1; i <= eap->line2; ++i)
3003 vim_free(ARGLIST[i - 1].ae_fname);
3004 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
3005 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
3006 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003007 if (curwin->w_arg_idx >= eap->line2)
3008 curwin->w_arg_idx -= n;
3009 else if (curwin->w_arg_idx > eap->line1)
3010 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01003011 if (ARGCOUNT == 0)
3012 curwin->w_arg_idx = 0;
3013 else if (curwin->w_arg_idx >= ARGCOUNT)
3014 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003015 }
3016 }
3017 else if (*eap->arg == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003018 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003019 else
Bram Moolenaar32bbd002018-08-31 23:06:22 +02003020 do_arglist(eap->arg, AL_DEL, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021#ifdef FEAT_TITLE
3022 maketitle();
3023#endif
3024}
3025
3026/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003027 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003028 */
3029 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003030ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003031{
3032 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003033 win_T *wp;
3034 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +01003035 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003036 int next_fnum = 0;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003037#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003038 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003039#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003040 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003041#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02003042 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003043 int qf_idx;
3044#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003045
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01003046#ifndef FEAT_QUICKFIX
3047 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
3048 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
3049 {
3050 ex_ni(eap);
3051 return;
3052 }
3053#endif
3054
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003055#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003056 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00003057 /* Don't do syntax HL autocommands. Skipping the syntax file is a
3058 * great speed improvement. */
3059 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003060#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02003061#ifdef FEAT_CLIPBOARD
3062 start_global_changes();
3063#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003064
3065 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003066 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +02003067 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01003068 || !check_changed(curbuf, CCGD_AW
3069 | (eap->forceit ? CCGD_FORCEIT : 0)
3070 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01003073 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003074 wp = firstwin;
3075 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +01003076 switch (eap->cmdidx)
3077 {
Bram Moolenaara162bc52015-01-07 16:54:21 +01003078 case CMD_windo:
3079 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
3080 i++;
3081 break;
3082 case CMD_tabdo:
3083 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
3084 i++;
3085 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01003086 case CMD_argdo:
3087 i = eap->line1 - 1;
3088 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01003089 default:
3090 break;
3091 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003092 /* set pcmark now */
3093 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003094 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01003095 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003096 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01003097 || !buf->b_p_bl); buf = buf->b_next)
3098 if (buf->b_fnum > eap->line2)
3099 {
3100 buf = NULL;
3101 break;
3102 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003103 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01003104 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003105 }
3106#ifdef FEAT_QUICKFIX
3107 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
3108 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
3109 {
3110 qf_size = qf_get_size(eap);
3111 if (qf_size <= 0 || eap->line1 > qf_size)
3112 buf = NULL;
3113 else
3114 {
3115 ex_cc(eap);
3116
3117 buf = curbuf;
3118 i = eap->line1 - 1;
3119 if (eap->addr_count <= 0)
3120 /* default is all the quickfix/location list entries */
3121 eap->line2 = qf_size;
3122 }
3123 }
3124#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003125 else
3126 setpcmark();
3127 listcmd_busy = TRUE; /* avoids setting pcmark below */
3128
Bram Moolenaare25bb902015-02-27 20:33:37 +01003129 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130 {
3131 if (eap->cmdidx == CMD_argdo)
3132 {
3133 /* go to argument "i" */
3134 if (i == ARGCOUNT)
3135 break;
3136 /* Don't call do_argfile() when already there, it will try
3137 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00003138 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003139 {
3140 /* Clear 'shm' to avoid that the file message overwrites
3141 * any output from the command. */
3142 p_shm_save = vim_strsave(p_shm);
3143 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003144 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003145 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
3146 vim_free(p_shm_save);
3147 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148 if (curwin->w_arg_idx != i)
3149 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003151 else if (eap->cmdidx == CMD_windo)
3152 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003153 /* go to window "wp" */
3154 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003155 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003156 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00003157 if (curwin != wp)
3158 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003159 wp = curwin->w_next;
3160 }
3161 else if (eap->cmdidx == CMD_tabdo)
3162 {
3163 /* go to window "tp" */
3164 if (!valid_tabpage(tp))
3165 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003166 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003167 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003168 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003169 else if (eap->cmdidx == CMD_bufdo)
3170 {
3171 /* Remember the number of the next listed buffer, in case
3172 * ":bwipe" is used or autocommands do something strange. */
3173 next_fnum = -1;
3174 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
3175 if (buf->b_p_bl)
3176 {
3177 next_fnum = buf->b_fnum;
3178 break;
3179 }
3180 }
3181
Bram Moolenaara162bc52015-01-07 16:54:21 +01003182 ++i;
3183
Bram Moolenaar071d4272004-06-13 20:20:40 +00003184 /* execute the command */
3185 do_cmdline(eap->arg, eap->getline, eap->cookie,
3186 DOCMD_VERBOSE + DOCMD_NOWAIT);
3187
3188 if (eap->cmdidx == CMD_bufdo)
3189 {
3190 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01003191 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192 break;
3193 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02003194 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003195 if (buf->b_fnum == next_fnum)
3196 break;
3197 if (buf == NULL)
3198 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003199
3200 /* Go to the next buffer. Clear 'shm' to avoid that the file
3201 * message overwrites any output from the command. */
3202 p_shm_save = vim_strsave(p_shm);
3203 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003205 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
3206 vim_free(p_shm_save);
3207
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003208 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003209 if (curbuf->b_fnum != next_fnum)
3210 break;
3211 }
3212
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003213#ifdef FEAT_QUICKFIX
3214 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
3215 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
3216 {
3217 if (i >= qf_size || i >= eap->line2)
3218 break;
3219
3220 qf_idx = qf_get_cur_idx(eap);
3221
3222 ex_cnext(eap);
3223
3224 /* If jumping to the next quickfix entry fails, quit here */
3225 if (qf_get_cur_idx(eap) == qf_idx)
3226 break;
3227 }
3228#endif
3229
Bram Moolenaar071d4272004-06-13 20:20:40 +00003230 if (eap->cmdidx == CMD_windo)
3231 {
3232 validate_cursor(); /* cursor may have moved */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01003233
Bram Moolenaar071d4272004-06-13 20:20:40 +00003234 /* required when 'scrollbind' has been set */
3235 if (curwin->w_p_scb)
3236 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01003238
Bram Moolenaara162bc52015-01-07 16:54:21 +01003239 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
3240 if (i+1 > eap->line2)
3241 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01003242 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
3243 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003244 }
3245 listcmd_busy = FALSE;
3246 }
3247
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003248#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003249 if (save_ei != NULL)
3250 {
3251 au_event_restore(save_ei);
3252 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
3253 curbuf->b_fname, TRUE, curbuf);
3254 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003255#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02003256#ifdef FEAT_CLIPBOARD
3257 end_global_changes();
3258#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003259}
3260
3261/*
3262 * Add files[count] to the arglist of the current window after arg "after".
3263 * The file names in files[count] must have been allocated and are taken over.
3264 * Files[] itself is not taken over.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265 */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02003266 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003267alist_add_list(
3268 int count,
3269 char_u **files,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02003270 int after, // where to add: 0 = before first one
3271 int will_edit) // will edit adding argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272{
3273 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003274 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003275
3276 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
3277 {
3278 if (after < 0)
3279 after = 0;
3280 if (after > ARGCOUNT)
3281 after = ARGCOUNT;
3282 if (after < ARGCOUNT)
3283 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
3284 (ARGCOUNT - after) * sizeof(aentry_T));
3285 for (i = 0; i < count; ++i)
3286 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02003287 int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0);
3288
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289 ARGLIST[after + i].ae_fname = files[i];
Bram Moolenaar32bbd002018-08-31 23:06:22 +02003290 ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291 }
3292 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003293 if (old_argcount > 0 && curwin->w_arg_idx >= after)
3294 curwin->w_arg_idx += count;
Bram Moolenaar32bbd002018-08-31 23:06:22 +02003295 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003296 }
3297
3298 for (i = 0; i < count; ++i)
3299 vim_free(files[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003300}
3301
Bram Moolenaarcd43eff2018-03-29 15:55:38 +02003302#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
3303/*
3304 * Function given to ExpandGeneric() to obtain the possible arguments of the
3305 * argedit and argdelete commands.
3306 */
3307 char_u *
3308get_arglist_name(expand_T *xp UNUSED, int idx)
3309{
3310 if (idx >= ARGCOUNT)
3311 return NULL;
3312
3313 return alist_name(&ARGLIST[idx]);
3314}
3315#endif
3316
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02003317
Bram Moolenaar071d4272004-06-13 20:20:40 +00003318#ifdef FEAT_EVAL
3319/*
3320 * ":compiler[!] {name}"
3321 */
3322 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003323ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324{
3325 char_u *buf;
3326 char_u *old_cur_comp = NULL;
3327 char_u *p;
3328
3329 if (*eap->arg == NUL)
3330 {
3331 /* List all compiler scripts. */
3332 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
3333 /* ) keep the indenter happy... */
3334 }
3335 else
3336 {
3337 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
3338 if (buf != NULL)
3339 {
3340 if (eap->forceit)
3341 {
3342 /* ":compiler! {name}" sets global options */
3343 do_cmdline_cmd((char_u *)
3344 "command -nargs=* CompilerSet set <args>");
3345 }
3346 else
3347 {
3348 /* ":compiler! {name}" sets local options.
3349 * To remain backwards compatible "current_compiler" is always
3350 * used. A user's compiler plugin may set it, the distributed
3351 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003352 * "b:current_compiler" and restore "current_compiler".
3353 * Explicitly prepend "g:" to make it work in a function. */
3354 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003355 if (old_cur_comp != NULL)
3356 old_cur_comp = vim_strsave(old_cur_comp);
3357 do_cmdline_cmd((char_u *)
3358 "command -nargs=* CompilerSet setlocal <args>");
3359 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003360 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00003361 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003362
3363 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003364 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003365 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003366 vim_free(buf);
3367
3368 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
3369
3370 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003371 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003372 if (p != NULL)
3373 set_internal_string_var((char_u *)"b:current_compiler", p);
3374
3375 /* Restore "current_compiler" for ":compiler {name}". */
3376 if (!eap->forceit)
3377 {
3378 if (old_cur_comp != NULL)
3379 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003380 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381 old_cur_comp);
3382 vim_free(old_cur_comp);
3383 }
3384 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003385 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003386 }
3387 }
3388 }
3389}
3390#endif
3391
3392/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003393 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003394 */
3395 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003396ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003397{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003398 char_u *arg = eap->arg;
3399 char_u *p = skiptowhite(arg);
3400 int len = (int)(p - arg);
3401 int flags = eap->forceit ? DIP_ALL : 0;
3402
3403 if (STRNCMP(arg, "START", len) == 0)
3404 {
3405 flags += DIP_START + DIP_NORTP;
3406 arg = skipwhite(arg + len);
3407 }
3408 else if (STRNCMP(arg, "OPT", len) == 0)
3409 {
3410 flags += DIP_OPT + DIP_NORTP;
3411 arg = skipwhite(arg + len);
3412 }
3413 else if (STRNCMP(arg, "PACK", len) == 0)
3414 {
3415 flags += DIP_START + DIP_OPT + DIP_NORTP;
3416 arg = skipwhite(arg + len);
3417 }
3418 else if (STRNCMP(arg, "ALL", len) == 0)
3419 {
3420 flags += DIP_START + DIP_OPT;
3421 arg = skipwhite(arg + len);
3422 }
3423
3424 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003425}
3426
Bram Moolenaar071d4272004-06-13 20:20:40 +00003427 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003428source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003429{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003430 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003431}
3432
3433/*
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003434 * Find the file "name" in all directories in "path" and invoke
3435 * "callback(fname, cookie)".
3436 * "name" can contain wildcards.
3437 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3438 * When "flags" has DIP_DIR: find directories instead of files.
3439 * When "flags" has DIP_ERR: give an error message if there is no match.
3440 *
3441 * return FAIL when no file could be sourced, OK otherwise.
3442 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01003443 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003444do_in_path(
3445 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003446 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01003447 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003448 void (*callback)(char_u *fname, void *ck),
3449 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003450{
3451 char_u *rtp;
3452 char_u *np;
3453 char_u *buf;
3454 char_u *rtp_copy;
3455 char_u *tail;
3456 int num_files;
3457 char_u **files;
3458 int i;
3459 int did_one = FALSE;
3460#ifdef AMIGA
3461 struct Process *proc = (struct Process *)FindTask(0L);
3462 APTR save_winptr = proc->pr_WindowPtr;
3463
3464 /* Avoid a requester here for a volume that doesn't exist. */
3465 proc->pr_WindowPtr = (APTR)-1L;
3466#endif
3467
3468 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3469 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003470 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471 buf = alloc(MAXPATHL);
3472 if (buf != NULL && rtp_copy != NULL)
3473 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003474 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003475 {
3476 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003477 smsg(_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003478 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003479 verbose_leave();
3480 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003481
Bram Moolenaar071d4272004-06-13 20:20:40 +00003482 /* Loop over all entries in 'runtimepath'. */
3483 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01003484 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003485 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02003486 size_t buflen;
3487
Bram Moolenaar071d4272004-06-13 20:20:40 +00003488 /* Copy the path from 'runtimepath' to buf[]. */
3489 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02003490 buflen = STRLEN(buf);
3491
3492 /* Skip after or non-after directories. */
3493 if (flags & (DIP_NOAFTER | DIP_AFTER))
3494 {
3495 int is_after = buflen >= 5
3496 && STRCMP(buf + buflen - 5, "after") == 0;
3497
3498 if ((is_after && (flags & DIP_NOAFTER))
3499 || (!is_after && (flags & DIP_AFTER)))
3500 continue;
3501 }
3502
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003503 if (name == NULL)
3504 {
3505 (*callback)(buf, (void *) &cookie);
3506 if (!did_one)
3507 did_one = (cookie == NULL);
3508 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02003509 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003510 {
3511 add_pathsep(buf);
3512 tail = buf + STRLEN(buf);
3513
3514 /* Loop over all patterns in "name" */
3515 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01003516 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003517 {
3518 /* Append the pattern from "name" to buf[]. */
3519 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3520 "\t ");
3521
3522 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003523 {
3524 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003525 smsg(_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003526 verbose_leave();
3527 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003528
3529 /* Expand wildcards, invoke the callback for each match. */
3530 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01003531 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003532 {
3533 for (i = 0; i < num_files; ++i)
3534 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003535 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003536 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01003537 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538 break;
3539 }
3540 FreeWild(num_files, files);
3541 }
3542 }
3543 }
3544 }
3545 }
3546 vim_free(buf);
3547 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003548 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003549 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003550 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
3551
3552 if (flags & DIP_ERR)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003553 semsg(_(e_dirnotf), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003554 else if (p_verbose > 0)
3555 {
3556 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003557 smsg(_("not found in '%s': \"%s\""), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003558 verbose_leave();
3559 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003560 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003561
3562#ifdef AMIGA
3563 proc->pr_WindowPtr = save_winptr;
3564#endif
3565
3566 return did_one ? OK : FAIL;
3567}
3568
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003569/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003570 * Find "name" in "path". When found, invoke the callback function for
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003571 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003572 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
3573 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003574 * Returns OK when at least one match found, FAIL otherwise.
3575 *
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003576 * If "name" is NULL calls callback for each entry in "path". Cookie is
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003577 * passed by reference in this case, setting it to NULL indicates that callback
3578 * has done its job.
3579 */
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003580 static int
3581do_in_path_and_pp(
3582 char_u *path,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003583 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003584 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003585 void (*callback)(char_u *fname, void *ck),
3586 void *cookie)
3587{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003588 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003589 char_u *s;
3590 int len;
3591 char *start_dir = "pack/*/start/*/%s";
3592 char *opt_dir = "pack/*/opt/*/%s";
3593
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003594 if ((flags & DIP_NORTP) == 0)
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003595 done = do_in_path(path, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003596
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003597 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003598 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003599 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003600 s = alloc(len);
3601 if (s == NULL)
3602 return FAIL;
3603 vim_snprintf((char *)s, len, start_dir, name);
3604 done = do_in_path(p_pp, s, flags, callback, cookie);
3605 vim_free(s);
3606 }
3607
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003608 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003609 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003610 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003611 s = alloc(len);
3612 if (s == NULL)
3613 return FAIL;
3614 vim_snprintf((char *)s, len, opt_dir, name);
3615 done = do_in_path(p_pp, s, flags, callback, cookie);
3616 vim_free(s);
3617 }
3618
3619 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003620}
3621
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003622/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003623 * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
3624 */
3625 int
3626do_in_runtimepath(
3627 char_u *name,
3628 int flags,
3629 void (*callback)(char_u *fname, void *ck),
3630 void *cookie)
3631{
3632 return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
3633}
3634
3635/*
3636 * Source the file "name" from all directories in 'runtimepath'.
3637 * "name" can contain wildcards.
3638 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3639 *
3640 * return FAIL when no file could be sourced, OK otherwise.
3641 */
3642 int
3643source_runtime(char_u *name, int flags)
3644{
3645 return source_in_path(p_rtp, name, flags);
3646}
3647
3648/*
3649 * Just like source_runtime(), but use "path" instead of 'runtimepath'.
3650 */
3651 int
3652source_in_path(char_u *path, char_u *name, int flags)
3653{
3654 return do_in_path_and_pp(path, name, flags, source_callback, NULL);
3655}
3656
3657
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003658#if defined(FEAT_EVAL) || defined(PROTO)
3659
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003660/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003661 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003662 */
3663 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01003664source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003665{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003666 int num_files;
3667 char_u **files;
3668 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003669
Bram Moolenaarf3654822016-03-04 22:12:23 +01003670 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003671 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01003672 for (i = 0; i < num_files; ++i)
3673 (void)do_source(files[i], FALSE, DOSO_NONE);
3674 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003675 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003676}
3677
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003678/*
3679 * Add the package directory to 'runtimepath'.
3680 */
3681 static int
3682add_pack_dir_to_rtp(char_u *fname)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003683{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003684 char_u *p4, *p3, *p2, *p1, *p;
Bram Moolenaar99396d42018-09-08 18:21:16 +02003685 char_u *entry;
3686 char_u *insp = NULL;
Bram Moolenaar91715872016-03-03 17:13:03 +01003687 int c;
3688 char_u *new_rtp;
3689 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003690 size_t oldlen;
3691 size_t addlen;
Bram Moolenaar99396d42018-09-08 18:21:16 +02003692 size_t new_rtp_len;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003693 char_u *afterdir = NULL;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003694 size_t afterlen = 0;
Bram Moolenaar99396d42018-09-08 18:21:16 +02003695 char_u *after_insp = NULL;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003696 char_u *ffname = NULL;
Bram Moolenaarfef524b2016-07-02 22:07:22 +02003697 size_t fname_len;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003698 char_u *buf = NULL;
3699 char_u *rtp_ffname;
3700 int match;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003701 int retval = FAIL;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003702
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003703 p4 = p3 = p2 = p1 = get_past_head(fname);
3704 for (p = p1; *p; MB_PTR_ADV(p))
3705 if (vim_ispathsep_nocolon(*p))
3706 {
3707 p4 = p3; p3 = p2; p2 = p1; p1 = p;
3708 }
3709
3710 /* now we have:
3711 * rtp/pack/name/start/name
3712 * p4 p3 p2 p1
3713 *
3714 * find the part up to "pack" in 'runtimepath' */
3715 c = *++p4; /* append pathsep in order to expand symlink */
3716 *p4 = NUL;
3717 ffname = fix_fname(fname);
3718 *p4 = c;
Bram Moolenaar91715872016-03-03 17:13:03 +01003719 if (ffname == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003720 return FAIL;
3721
Bram Moolenaar99396d42018-09-08 18:21:16 +02003722 // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences.
3723 // Also stop at the first "after" directory.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003724 fname_len = STRLEN(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003725 buf = alloc(MAXPATHL);
3726 if (buf == NULL)
3727 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02003728 for (entry = p_rtp; *entry != NUL; )
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003729 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02003730 char_u *cur_entry = entry;
3731
3732 copy_option_part(&entry, buf, MAXPATHL, ",");
3733 if (insp == NULL)
3734 {
3735 add_pathsep(buf);
3736 rtp_ffname = fix_fname(buf);
3737 if (rtp_ffname == NULL)
3738 goto theend;
3739 match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
3740 vim_free(rtp_ffname);
3741 if (match)
3742 // Insert "ffname" after this entry (and comma).
3743 insp = entry;
3744 }
3745
3746 if ((p = (char_u *)strstr((char *)buf, "after")) != NULL
3747 && p > buf
3748 && vim_ispathsep(p[-1])
3749 && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','))
3750 {
3751 if (insp == NULL)
3752 // Did not find "ffname" before the first "after" directory,
3753 // insert it before this entry.
3754 insp = cur_entry;
3755 after_insp = cur_entry;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003756 break;
Bram Moolenaar99396d42018-09-08 18:21:16 +02003757 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003758 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003759
Bram Moolenaar99396d42018-09-08 18:21:16 +02003760 if (insp == NULL)
3761 // Both "fname" and "after" not found, append at the end.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003762 insp = p_rtp + STRLEN(p_rtp);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003763
Bram Moolenaar99396d42018-09-08 18:21:16 +02003764 // check if rtp/pack/name/start/name/after exists
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003765 afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
3766 if (afterdir != NULL && mch_isdir(afterdir))
Bram Moolenaar99396d42018-09-08 18:21:16 +02003767 afterlen = STRLEN(afterdir) + 1; // add one for comma
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003768
3769 oldlen = STRLEN(p_rtp);
Bram Moolenaar99396d42018-09-08 18:21:16 +02003770 addlen = STRLEN(fname) + 1; // add one for comma
3771 new_rtp = alloc((int)(oldlen + addlen + afterlen + 1)); // add one for NUL
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003772 if (new_rtp == NULL)
3773 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02003774
3775 // We now have 'rtp' parts: {keep}{keep_after}{rest}.
3776 // Create new_rtp, first: {keep},{fname}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003777 keep = (int)(insp - p_rtp);
3778 mch_memmove(new_rtp, p_rtp, keep);
Bram Moolenaar99396d42018-09-08 18:21:16 +02003779 new_rtp_len = keep;
3780 if (*insp == NUL)
3781 new_rtp[new_rtp_len++] = ','; // add comma before
3782 mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1);
3783 new_rtp_len += addlen - 1;
3784 if (*insp != NUL)
3785 new_rtp[new_rtp_len++] = ','; // add comma after
3786
3787 if (afterlen > 0 && after_insp != NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003788 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02003789 int keep_after = (int)(after_insp - p_rtp);
3790
3791 // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
3792 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep,
3793 keep_after - keep);
3794 new_rtp_len += keep_after - keep;
3795 mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
3796 new_rtp_len += afterlen - 1;
3797 new_rtp[new_rtp_len++] = ',';
3798 keep = keep_after;
3799 }
3800
3801 if (p_rtp[keep] != NUL)
3802 // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
3803 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
3804 else
3805 new_rtp[new_rtp_len] = NUL;
3806
3807 if (afterlen > 0 && after_insp == NULL)
3808 {
3809 // Append afterdir when "after" was not found:
3810 // {keep},{fname}{rest},{afterdir}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003811 STRCAT(new_rtp, ",");
3812 STRCAT(new_rtp, afterdir);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003813 }
Bram Moolenaar99396d42018-09-08 18:21:16 +02003814
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003815 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3816 vim_free(new_rtp);
3817 retval = OK;
Bram Moolenaarf3654822016-03-04 22:12:23 +01003818
3819theend:
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003820 vim_free(buf);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003821 vim_free(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003822 vim_free(afterdir);
3823 return retval;
3824}
3825
3826/*
3827 * Load scripts in "plugin" and "ftdetect" directories of the package.
3828 */
3829 static int
3830load_pack_plugin(char_u *fname)
3831{
3832 static char *plugpat = "%s/plugin/**/*.vim";
3833 static char *ftpat = "%s/ftdetect/*.vim";
3834 int len;
3835 char_u *ffname = fix_fname(fname);
3836 char_u *pat = NULL;
3837 int retval = FAIL;
3838
3839 if (ffname == NULL)
3840 return FAIL;
3841 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3842 pat = alloc(len);
3843 if (pat == NULL)
3844 goto theend;
3845 vim_snprintf((char *)pat, len, plugpat, ffname);
3846 source_all_matches(pat);
3847
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003848 {
3849 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3850
3851 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3852 * found when it loads. */
3853 if (cmd != NULL && eval_to_number(cmd) > 0)
3854 {
3855 do_cmdline_cmd((char_u *)"augroup filetypedetect");
3856 vim_snprintf((char *)pat, len, ftpat, ffname);
3857 source_all_matches(pat);
3858 do_cmdline_cmd((char_u *)"augroup END");
3859 }
3860 vim_free(cmd);
3861 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003862 vim_free(pat);
3863 retval = OK;
3864
3865theend:
3866 vim_free(ffname);
3867 return retval;
3868}
3869
3870/* used for "cookie" of add_pack_plugin() */
3871static int APP_ADD_DIR;
3872static int APP_LOAD;
3873static int APP_BOTH;
3874
3875 static void
3876add_pack_plugin(char_u *fname, void *cookie)
3877{
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02003878 if (cookie != &APP_LOAD)
3879 {
3880 char_u *buf = alloc(MAXPATHL);
3881 char_u *p;
3882 int found = FALSE;
3883
3884 if (buf == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003885 return;
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02003886 p = p_rtp;
3887 while (*p != NUL)
3888 {
3889 copy_option_part(&p, buf, MAXPATHL, ",");
3890 if (pathcmp((char *)buf, (char *)fname, -1) == 0)
3891 {
3892 found = TRUE;
3893 break;
3894 }
3895 }
3896 vim_free(buf);
3897 if (!found)
3898 /* directory is not yet in 'runtimepath', add it */
3899 if (add_pack_dir_to_rtp(fname) == FAIL)
3900 return;
3901 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01003902
3903 if (cookie != &APP_ADD_DIR)
3904 load_pack_plugin(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003905}
3906
Bram Moolenaarce876aa2017-06-04 17:47:42 +02003907/*
3908 * Add all packages in the "start" directory to 'runtimepath'.
3909 */
3910 void
3911add_pack_start_dirs(void)
3912{
3913 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3914 add_pack_plugin, &APP_ADD_DIR);
3915}
3916
3917/*
3918 * Load plugins from all packages in the "start" directory.
3919 */
3920 void
3921load_start_packages(void)
3922{
3923 did_source_packages = TRUE;
3924 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3925 add_pack_plugin, &APP_LOAD);
3926}
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003927
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003928/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003929 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01003930 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003931 */
3932 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003933ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003934{
Bram Moolenaarce876aa2017-06-04 17:47:42 +02003935 if (!did_source_packages || eap->forceit)
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003936 {
Bram Moolenaar49b27322016-04-05 21:13:00 +02003937 /* First do a round to add all directories to 'runtimepath', then load
3938 * the plugins. This allows for plugins to use an autoload directory
3939 * of another plugin. */
Bram Moolenaarce876aa2017-06-04 17:47:42 +02003940 add_pack_start_dirs();
3941 load_start_packages();
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003942 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003943}
3944
3945/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003946 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01003947 */
3948 void
3949ex_packadd(exarg_T *eap)
3950{
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01003951 static char *plugpat = "pack/*/%s/%s";
Bram Moolenaar91715872016-03-03 17:13:03 +01003952 int len;
3953 char *pat;
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01003954 int round;
3955 int res = OK;
Bram Moolenaar91715872016-03-03 17:13:03 +01003956
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01003957 /* Round 1: use "start", round 2: use "opt". */
3958 for (round = 1; round <= 2; ++round)
3959 {
3960 /* Only look under "start" when loading packages wasn't done yet. */
3961 if (round == 1 && did_source_packages)
3962 continue;
3963
3964 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg) + 5;
3965 pat = (char *)alloc(len);
3966 if (pat == NULL)
3967 return;
3968 vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
3969 /* The first round don't give a "not found" error, in the second round
3970 * only when nothing was found in the first round. */
3971 res = do_in_path(p_pp, (char_u *)pat,
3972 DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
3973 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
3974 vim_free(pat);
3975 }
Bram Moolenaar91715872016-03-03 17:13:03 +01003976}
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003977#endif
Bram Moolenaar91715872016-03-03 17:13:03 +01003978
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003979#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003980/*
3981 * ":options"
3982 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003983 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003984ex_options(
3985 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003986{
Bram Moolenaarab6c8582017-08-11 17:15:09 +02003987 vim_setenv((char_u *)"OPTWIN_CMD", (char_u *)(cmdmod.tab ? "tab" : ""));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003988 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3989}
3990#endif
3991
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003992#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
3993
3994# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
3995/*
3996 * Detect Python 3 or 2, and initialize 'pyxversion'.
3997 */
3998 void
3999init_pyxversion(void)
4000{
4001 if (p_pyx == 0)
4002 {
4003 if (python3_enabled(FALSE))
4004 p_pyx = 3;
4005 else if (python_enabled(FALSE))
4006 p_pyx = 2;
4007 }
4008}
4009# endif
4010
4011/*
4012 * Does a file contain one of the following strings at the beginning of any
4013 * line?
4014 * "#!(any string)python2" => returns 2
4015 * "#!(any string)python3" => returns 3
4016 * "# requires python 2.x" => returns 2
4017 * "# requires python 3.x" => returns 3
4018 * otherwise return 0.
4019 */
4020 static int
4021requires_py_version(char_u *filename)
4022{
4023 FILE *file;
4024 int requires_py_version = 0;
4025 int i, lines;
4026
4027 lines = (int)p_mls;
4028 if (lines < 0)
4029 lines = 5;
4030
4031 file = mch_fopen((char *)filename, "r");
4032 if (file != NULL)
4033 {
4034 for (i = 0; i < lines; i++)
4035 {
4036 if (vim_fgets(IObuff, IOSIZE, file))
4037 break;
4038 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
4039 {
4040 /* Check shebang. */
4041 if (strstr((char *)IObuff + 2, "python2") != NULL)
4042 {
4043 requires_py_version = 2;
4044 break;
4045 }
4046 if (strstr((char *)IObuff + 2, "python3") != NULL)
4047 {
4048 requires_py_version = 3;
4049 break;
4050 }
4051 }
4052 IObuff[21] = '\0';
4053 if (STRCMP("# requires python 2.x", IObuff) == 0)
4054 {
4055 requires_py_version = 2;
4056 break;
4057 }
4058 if (STRCMP("# requires python 3.x", IObuff) == 0)
4059 {
4060 requires_py_version = 3;
4061 break;
4062 }
4063 }
4064 fclose(file);
4065 }
4066 return requires_py_version;
4067}
4068
4069
4070/*
4071 * Source a python file using the requested python version.
4072 */
4073 static void
4074source_pyx_file(exarg_T *eap, char_u *fname)
4075{
4076 exarg_T ex;
4077 int v = requires_py_version(fname);
4078
4079# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
4080 init_pyxversion();
4081# endif
4082 if (v == 0)
4083 {
4084# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
4085 /* user didn't choose a preference, 'pyx' is used */
4086 v = p_pyx;
4087# elif defined(FEAT_PYTHON)
4088 v = 2;
4089# elif defined(FEAT_PYTHON3)
4090 v = 3;
4091# endif
4092 }
4093
4094 /*
4095 * now source, if required python version is not supported show
4096 * unobtrusive message.
4097 */
4098 if (eap == NULL)
4099 vim_memset(&ex, 0, sizeof(ex));
4100 else
4101 ex = *eap;
4102 ex.arg = fname;
4103 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
4104
4105 if (v == 2)
4106 {
4107# ifdef FEAT_PYTHON
4108 ex_pyfile(&ex);
4109# else
4110 vim_snprintf((char *)IObuff, IOSIZE,
4111 _("W20: Required python version 2.x not supported, ignoring file: %s"),
4112 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01004113 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004114# endif
4115 return;
4116 }
4117 else
4118 {
4119# ifdef FEAT_PYTHON3
4120 ex_py3file(&ex);
4121# else
4122 vim_snprintf((char *)IObuff, IOSIZE,
4123 _("W21: Required python version 3.x not supported, ignoring file: %s"),
4124 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01004125 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004126# endif
4127 return;
4128 }
4129}
4130
4131/*
4132 * ":pyxfile {fname}"
4133 */
4134 void
4135ex_pyxfile(exarg_T *eap)
4136{
4137 source_pyx_file(eap, eap->arg);
4138}
4139
4140/*
4141 * ":pyx"
4142 */
4143 void
4144ex_pyx(exarg_T *eap)
4145{
4146# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
4147 init_pyxversion();
4148 if (p_pyx == 2)
4149 ex_python(eap);
4150 else
4151 ex_py3(eap);
4152# elif defined(FEAT_PYTHON)
4153 ex_python(eap);
4154# elif defined(FEAT_PYTHON3)
4155 ex_py3(eap);
4156# endif
4157}
4158
4159/*
4160 * ":pyxdo"
4161 */
4162 void
4163ex_pyxdo(exarg_T *eap)
4164{
4165# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
4166 init_pyxversion();
4167 if (p_pyx == 2)
4168 ex_pydo(eap);
4169 else
4170 ex_py3do(eap);
4171# elif defined(FEAT_PYTHON)
4172 ex_pydo(eap);
4173# elif defined(FEAT_PYTHON3)
4174 ex_py3do(eap);
4175# endif
4176}
4177
4178#endif
4179
Bram Moolenaar071d4272004-06-13 20:20:40 +00004180/*
4181 * ":source {fname}"
4182 */
4183 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004184ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004185{
4186#ifdef FEAT_BROWSE
4187 if (cmdmod.browse)
4188 {
4189 char_u *fname = NULL;
4190
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00004191 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaarc36651b2018-04-29 12:22:56 +02004192 NULL, NULL,
4193 (char_u *)_(BROWSE_FILTER_MACROS), NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004194 if (fname != NULL)
4195 {
4196 cmd_source(fname, eap);
4197 vim_free(fname);
4198 }
4199 }
4200 else
4201#endif
4202 cmd_source(eap->arg, eap);
4203}
4204
4205 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004206cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004207{
4208 if (*fname == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004209 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004210
Bram Moolenaar071d4272004-06-13 20:20:40 +00004211 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02004212 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004213 * Need to execute the commands directly. This is required at least
4214 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00004215 * - ":g" command busy
4216 * - after ":argdo", ":windo" or ":bufdo"
4217 * - another command follows
4218 * - inside a loop
4219 */
4220 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
4221#ifdef FEAT_EVAL
4222 || eap->cstack->cs_idx >= 0
4223#endif
4224 );
4225
4226 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004227 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004228 semsg(_(e_notopen), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004229}
4230
4231/*
4232 * ":source" and associated commands.
4233 */
4234/*
4235 * Structure used to store info for each sourced file.
4236 * It is shared between do_source() and getsourceline().
4237 * This is required, because it needs to be handed to do_cmdline() and
4238 * sourcing can be done recursively.
4239 */
4240struct source_cookie
4241{
4242 FILE *fp; /* opened file for sourcing */
4243 char_u *nextline; /* if not NULL: line that was read ahead */
4244 int finished; /* ":finish" used */
Bram Moolenaar00590742019-02-15 21:06:09 +01004245#ifdef USE_CRNL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004246 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
4247 int error; /* TRUE if LF found after CR-LF */
4248#endif
4249#ifdef FEAT_EVAL
4250 linenr_T breakpoint; /* next line with breakpoint or zero */
4251 char_u *fname; /* name of sourced file */
4252 int dbg_tick; /* debug_tick when breakpoint was set */
4253 int level; /* top nesting level of sourced file */
4254#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004255 vimconv_T conv; /* type of conversion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004256};
4257
4258#ifdef FEAT_EVAL
4259/*
4260 * Return the address holding the next breakpoint line for a source cookie.
4261 */
4262 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004263source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004264{
4265 return &((struct source_cookie *)cookie)->breakpoint;
4266}
4267
4268/*
4269 * Return the address holding the debug tick for a source cookie.
4270 */
4271 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004272source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004273{
4274 return &((struct source_cookie *)cookie)->dbg_tick;
4275}
4276
4277/*
4278 * Return the nesting level for a source cookie.
4279 */
4280 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004281source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004282{
4283 return ((struct source_cookie *)cookie)->level;
4284}
4285#endif
4286
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004287static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004288
Bram Moolenaar4f974752019-02-17 17:44:42 +01004289#if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004290# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004291/*
4292 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004293 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004294 */
4295 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004296fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004297{
Bram Moolenaar4f974752019-02-17 17:44:42 +01004298# ifdef MSWIN
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01004299 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
4300# else
4301 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004302# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004303
4304 if (fd_tmp == -1)
4305 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004306
4307# ifdef HAVE_FD_CLOEXEC
4308 {
4309 int fdflags = fcntl(fd_tmp, F_GETFD);
4310 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02004311 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004312 }
4313# endif
4314
Bram Moolenaar071d4272004-06-13 20:20:40 +00004315 return fdopen(fd_tmp, READBIN);
4316}
4317#endif
4318
4319
4320/*
4321 * do_source: Read the file "fname" and execute its lines as EX commands.
4322 *
4323 * This function may be called recursively!
4324 *
4325 * return FAIL if file could not be opened, OK otherwise
4326 */
4327 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004328do_source(
4329 char_u *fname,
4330 int check_other, /* check for .vimrc and _vimrc */
4331 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004332{
4333 struct source_cookie cookie;
4334 char_u *save_sourcing_name;
4335 linenr_T save_sourcing_lnum;
4336 char_u *p;
4337 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00004338 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004339 int retval = FAIL;
4340#ifdef FEAT_EVAL
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004341 sctx_T save_current_sctx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004342 static scid_T last_current_SID = 0;
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01004343 static int last_current_SID_seq = 0;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02004344 funccal_entry_T funccalp_entry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004345 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004346 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004347# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02004348 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004349 int stat_ok;
4350# endif
4351#endif
4352#ifdef STARTUPTIME
4353 struct timeval tv_rel;
4354 struct timeval tv_start;
4355#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004356#ifdef FEAT_PROFILE
4357 proftime_T wait_start;
4358#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01004359 int trigger_source_post = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004360
Bram Moolenaar071d4272004-06-13 20:20:40 +00004361 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004362 if (p == NULL)
4363 return retval;
4364 fname_exp = fix_fname(p);
4365 vim_free(p);
4366 if (fname_exp == NULL)
4367 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004368 if (mch_isdir(fname_exp))
4369 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004370 smsg(_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004371 goto theend;
4372 }
4373
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004374 /* Apply SourceCmd autocommands, they should get the file and source it. */
4375 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
4376 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
4377 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004378 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004379#ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004380 retval = aborting() ? FAIL : OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004381#else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004382 retval = OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004383#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01004384 if (retval == OK)
4385 // Apply SourcePost autocommands.
4386 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp,
4387 FALSE, curbuf);
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004388 goto theend;
4389 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004390
4391 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004392 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004393
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004394#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004395 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
4396#else
4397 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
4398#endif
4399 if (cookie.fp == NULL && check_other)
4400 {
4401 /*
4402 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
4403 * and ".exrc" by "_exrc" or vice versa.
4404 */
4405 p = gettail(fname_exp);
4406 if ((*p == '.' || *p == '_')
4407 && (STRICMP(p + 1, "vimrc") == 0
4408 || STRICMP(p + 1, "gvimrc") == 0
4409 || STRICMP(p + 1, "exrc") == 0))
4410 {
4411 if (*p == '_')
4412 *p = '.';
4413 else
4414 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004415#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004416 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
4417#else
4418 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
4419#endif
4420 }
4421 }
4422
4423 if (cookie.fp == NULL)
4424 {
4425 if (p_verbose > 0)
4426 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004427 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004428 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004429 smsg(_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004430 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004431 smsg(_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00004432 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004433 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004434 }
4435 goto theend;
4436 }
4437
4438 /*
4439 * The file exists.
4440 * - In verbose mode, give a message.
4441 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
4442 */
4443 if (p_verbose > 1)
4444 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004445 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004446 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004447 smsg(_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004448 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004449 smsg(_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00004450 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004451 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004452 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004453 if (is_vimrc == DOSO_VIMRC)
4454 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
4455 else if (is_vimrc == DOSO_GVIMRC)
4456 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004457
4458#ifdef USE_CRNL
4459 /* If no automatic file format: Set default to CR-NL. */
4460 if (*p_ffs == NUL)
4461 cookie.fileformat = EOL_DOS;
4462 else
4463 cookie.fileformat = EOL_UNKNOWN;
4464 cookie.error = FALSE;
4465#endif
4466
Bram Moolenaar071d4272004-06-13 20:20:40 +00004467 cookie.nextline = NULL;
4468 cookie.finished = FALSE;
4469
4470#ifdef FEAT_EVAL
4471 /*
4472 * Check if this script has a breakpoint.
4473 */
4474 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
4475 cookie.fname = fname_exp;
4476 cookie.dbg_tick = debug_tick;
4477
4478 cookie.level = ex_nesting_level;
4479#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004480
4481 /*
4482 * Keep the sourcing name/lnum, for recursive calls.
4483 */
4484 save_sourcing_name = sourcing_name;
4485 sourcing_name = fname_exp;
4486 save_sourcing_lnum = sourcing_lnum;
4487 sourcing_lnum = 0;
4488
4489#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004490 if (time_fd != NULL)
4491 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004492#endif
4493
4494#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00004495# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004496 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004497 prof_child_enter(&wait_start); /* entering a child now */
4498# endif
4499
4500 /* Don't use local function variables, if called from a function.
4501 * Also starts profiling timer for nested script. */
Bram Moolenaar27e80c82018-10-14 21:41:01 +02004502 save_funccal(&funccalp_entry);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004503
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01004504 // Check if this script was sourced before to finds its SID.
4505 // If it's new, generate a new SID.
4506 // Always use a new sequence number.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004507 save_current_sctx = current_sctx;
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01004508 current_sctx.sc_seq = ++last_current_SID_seq;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004509 current_sctx.sc_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004510# ifdef UNIX
4511 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
4512# endif
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004513 for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
4514 --current_sctx.sc_sid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004515 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004516 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004517 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004518 && (
4519# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00004520 /* Compare dev/ino when possible, it catches symbolic
4521 * links. Also compare file names, the inode may change
4522 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004523 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004524 && (si->sn_dev == st.st_dev
4525 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00004526# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004527 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004528 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004529 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004530 if (current_sctx.sc_sid == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004531 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004532 current_sctx.sc_sid = ++last_current_SID;
4533 if (ga_grow(&script_items,
4534 (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004535 goto almosttheend;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004536 while (script_items.ga_len < current_sctx.sc_sid)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00004538 ++script_items.ga_len;
4539 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
4540# ifdef FEAT_PROFILE
4541 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004542# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004543 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004544 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004545 si->sn_name = fname_exp;
Bram Moolenaarea56e162019-01-12 15:15:38 +01004546 fname_exp = vim_strsave(si->sn_name); // used for autocmd
Bram Moolenaar05159a02005-02-26 23:04:13 +00004547# ifdef UNIX
4548 if (stat_ok)
4549 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004550 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004551 si->sn_dev = st.st_dev;
4552 si->sn_ino = st.st_ino;
4553 }
4554 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004555 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004556# endif
4557
Bram Moolenaar071d4272004-06-13 20:20:40 +00004558 /* Allocate the local script variables to use for this script. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004559 new_script_vars(current_sctx.sc_sid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004560 }
4561
Bram Moolenaar05159a02005-02-26 23:04:13 +00004562# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004563 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004564 {
4565 int forceit;
4566
4567 /* Check if we do profiling for this script. */
4568 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
4569 {
4570 script_do_profile(si);
4571 si->sn_pr_force = forceit;
4572 }
4573 if (si->sn_prof_on)
4574 {
4575 ++si->sn_pr_count;
4576 profile_start(&si->sn_pr_start);
4577 profile_zero(&si->sn_pr_children);
4578 }
4579 }
4580# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004581#endif
4582
Bram Moolenaar67435d92017-10-19 21:04:37 +02004583 cookie.conv.vc_type = CONV_NONE; /* no conversion */
4584
4585 /* Read the first line so we can check for a UTF-8 BOM. */
4586 firstline = getsourceline(0, (void *)&cookie, 0);
4587 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
4588 && firstline[1] == 0xbb && firstline[2] == 0xbf)
4589 {
4590 /* Found BOM; setup conversion, skip over BOM and recode the line. */
4591 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
4592 p = string_convert(&cookie.conv, firstline + 3, NULL);
4593 if (p == NULL)
4594 p = vim_strsave(firstline + 3);
4595 if (p != NULL)
4596 {
4597 vim_free(firstline);
4598 firstline = p;
4599 }
4600 }
Bram Moolenaar67435d92017-10-19 21:04:37 +02004601
Bram Moolenaar071d4272004-06-13 20:20:40 +00004602 /*
4603 * Call do_cmdline, which will call getsourceline() to get the lines.
4604 */
Bram Moolenaar73881402009-02-04 16:50:47 +00004605 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004606 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004607 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004608
4609#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004610 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004611 {
4612 /* Get "si" again, "script_items" may have been reallocated. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004613 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004614 if (si->sn_prof_on)
4615 {
4616 profile_end(&si->sn_pr_start);
4617 profile_sub_wait(&wait_start, &si->sn_pr_start);
4618 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004619 profile_self(&si->sn_pr_self, &si->sn_pr_start,
4620 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004621 }
4622 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623#endif
4624
4625 if (got_int)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004626 emsg(_(e_interr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 sourcing_name = save_sourcing_name;
4628 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004629 if (p_verbose > 1)
4630 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004631 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004632 smsg(_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004633 if (sourcing_name != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004634 smsg(_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004635 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004636 }
4637#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004638 if (time_fd != NULL)
4639 {
4640 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
4641 time_msg((char *)IObuff, &tv_start);
4642 time_pop(&tv_rel);
4643 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644#endif
4645
Bram Moolenaar2b618522019-01-12 13:26:03 +01004646 if (!got_int)
4647 trigger_source_post = TRUE;
4648
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649#ifdef FEAT_EVAL
4650 /*
4651 * After a "finish" in debug mode, need to break at first command of next
4652 * sourced file.
4653 */
4654 if (save_debug_break_level > ex_nesting_level
4655 && debug_break_level == ex_nesting_level)
4656 ++debug_break_level;
4657#endif
4658
Bram Moolenaar05159a02005-02-26 23:04:13 +00004659#ifdef FEAT_EVAL
4660almosttheend:
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004661 current_sctx = save_current_sctx;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02004662 restore_funccal();
Bram Moolenaar05159a02005-02-26 23:04:13 +00004663# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004664 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004665 prof_child_exit(&wait_start); /* leaving a child now */
4666# endif
4667#endif
4668 fclose(cookie.fp);
4669 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00004670 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004671 convert_setup(&cookie.conv, NULL, NULL);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004672
Bram Moolenaar2b618522019-01-12 13:26:03 +01004673 if (trigger_source_post)
Bram Moolenaarea56e162019-01-12 15:15:38 +01004674 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar2b618522019-01-12 13:26:03 +01004675
Bram Moolenaar071d4272004-06-13 20:20:40 +00004676theend:
4677 vim_free(fname_exp);
4678 return retval;
4679}
4680
4681#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004682
Bram Moolenaar071d4272004-06-13 20:20:40 +00004683/*
4684 * ":scriptnames"
4685 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004686 void
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01004687ex_scriptnames(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004688{
4689 int i;
4690
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01004691 if (eap->addr_count > 0)
4692 {
4693 // :script {scriptId}: edit the script
4694 if (eap->line2 < 1 || eap->line2 > script_items.ga_len)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004695 emsg(_(e_invarg));
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01004696 else
4697 {
4698 eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
4699 do_exedit(eap, NULL);
4700 }
4701 return;
4702 }
4703
Bram Moolenaar05159a02005-02-26 23:04:13 +00004704 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
4705 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02004706 {
4707 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
4708 NameBuff, MAXPATHL, TRUE);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004709 smsg("%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01004710 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004711}
4712
4713# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
4714/*
4715 * Fix slashes in the list of script names for 'shellslash'.
4716 */
4717 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004718scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004719{
4720 int i;
4721
Bram Moolenaar05159a02005-02-26 23:04:13 +00004722 for (i = 1; i <= script_items.ga_len; ++i)
4723 if (SCRIPT_ITEM(i).sn_name != NULL)
4724 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004725}
4726# endif
4727
4728/*
4729 * Get a pointer to a script name. Used for ":verbose set".
4730 */
4731 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004732get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004733{
4734 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004735 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004736 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004737 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004738 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004739 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004740 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004741 return (char_u *)_("environment variable");
4742 if (id == SID_ERROR)
4743 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004744 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004745}
Bram Moolenaar05159a02005-02-26 23:04:13 +00004746
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004747# if defined(EXITFREE) || defined(PROTO)
4748 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004749free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004750{
4751 int i;
4752
4753 for (i = script_items.ga_len; i > 0; --i)
4754 vim_free(SCRIPT_ITEM(i).sn_name);
4755 ga_clear(&script_items);
4756}
4757# endif
4758
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759#endif
4760
Bram Moolenaar071d4272004-06-13 20:20:40 +00004761/*
4762 * Get one full line from a sourced file.
4763 * Called by do_cmdline() when it's called from do_source().
4764 *
4765 * Return a pointer to the line in allocated memory.
4766 * Return NULL for end-of-file or some error.
4767 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004768 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004769getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004770{
4771 struct source_cookie *sp = (struct source_cookie *)cookie;
4772 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004773 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004774
4775#ifdef FEAT_EVAL
4776 /* If breakpoints have been added/deleted need to check for it. */
4777 if (sp->dbg_tick < debug_tick)
4778 {
4779 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4780 sp->dbg_tick = debug_tick;
4781 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004782# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004783 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004784 script_line_end();
4785# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786#endif
4787 /*
4788 * Get current line. If there is a read-ahead line, use it, otherwise get
4789 * one now.
4790 */
4791 if (sp->finished)
4792 line = NULL;
4793 else if (sp->nextline == NULL)
4794 line = get_one_sourceline(sp);
4795 else
4796 {
4797 line = sp->nextline;
4798 sp->nextline = NULL;
4799 ++sourcing_lnum;
4800 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004801#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004802 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004803 script_line_start();
4804#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004805
4806 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
4807 * contain the 'C' flag. */
4808 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
4809 {
4810 /* compensate for the one line read-ahead */
4811 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004812
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02004813 // Get the next line and concatenate it when it starts with a
4814 // backslash. We always need to read the next line, keep it in
4815 // sp->nextline.
4816 /* Also check for a comment in between continuation lines: "\ */
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004817 sp->nextline = get_one_sourceline(sp);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02004818 if (sp->nextline != NULL
4819 && (*(p = skipwhite(sp->nextline)) == '\\'
4820 || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004821 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004822 garray_T ga;
4823
Bram Moolenaarb549a732012-02-22 18:29:33 +01004824 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004825 ga_concat(&ga, line);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02004826 if (*p == '\\')
4827 ga_concat(&ga, p + 1);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004828 for (;;)
4829 {
4830 vim_free(sp->nextline);
4831 sp->nextline = get_one_sourceline(sp);
4832 if (sp->nextline == NULL)
4833 break;
4834 p = skipwhite(sp->nextline);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02004835 if (*p == '\\')
Bram Moolenaarb549a732012-02-22 18:29:33 +01004836 {
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02004837 // Adjust the growsize to the current length to speed up
4838 // concatenating many lines.
4839 if (ga.ga_len > 400)
4840 {
4841 if (ga.ga_len > 8000)
4842 ga.ga_growsize = 8000;
4843 else
4844 ga.ga_growsize = ga.ga_len;
4845 }
4846 ga_concat(&ga, p + 1);
Bram Moolenaarb549a732012-02-22 18:29:33 +01004847 }
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02004848 else if (p[0] != '"' || p[1] != '\\' || p[2] != ' ')
4849 break;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004850 }
4851 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004852 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004853 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004854 }
4855 }
4856
Bram Moolenaar071d4272004-06-13 20:20:40 +00004857 if (line != NULL && sp->conv.vc_type != CONV_NONE)
4858 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004859 char_u *s;
4860
Bram Moolenaar071d4272004-06-13 20:20:40 +00004861 /* Convert the encoding of the script line. */
4862 s = string_convert(&sp->conv, line, NULL);
4863 if (s != NULL)
4864 {
4865 vim_free(line);
4866 line = s;
4867 }
4868 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004869
4870#ifdef FEAT_EVAL
4871 /* Did we encounter a breakpoint? */
4872 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
4873 {
4874 dbg_breakpoint(sp->fname, sourcing_lnum);
4875 /* Find next breakpoint. */
4876 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4877 sp->dbg_tick = debug_tick;
4878 }
4879#endif
4880
4881 return line;
4882}
4883
4884 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004885get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004886{
4887 garray_T ga;
4888 int len;
4889 int c;
4890 char_u *buf;
4891#ifdef USE_CRNL
4892 int has_cr; /* CR-LF found */
4893#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004894 int have_read = FALSE;
4895
4896 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004897 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004898
4899 /*
4900 * Loop until there is a finished line (or end-of-file).
4901 */
4902 sourcing_lnum++;
4903 for (;;)
4904 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004905 /* make room to read at least 120 (more) characters */
4906 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004907 break;
4908 buf = (char_u *)ga.ga_data;
4909
Bram Moolenaar00590742019-02-15 21:06:09 +01004910 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
Bram Moolenaar86b68352004-12-27 21:59:20 +00004911 sp->fp) == NULL)
Bram Moolenaar00590742019-02-15 21:06:09 +01004912 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004913 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004914#ifdef USE_CRNL
4915 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
4916 * CTRL-Z by its own, or after a NL. */
4917 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
4918 && sp->fileformat == EOL_DOS
4919 && buf[len - 1] == Ctrl_Z)
4920 {
4921 buf[len - 1] = NUL;
4922 break;
4923 }
4924#endif
4925
Bram Moolenaar071d4272004-06-13 20:20:40 +00004926 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004927 ga.ga_len = len;
4928
4929 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00004930 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004931 continue;
4932
4933 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
4934 {
4935#ifdef USE_CRNL
4936 has_cr = (len >= 2 && buf[len - 2] == '\r');
4937 if (sp->fileformat == EOL_UNKNOWN)
4938 {
4939 if (has_cr)
4940 sp->fileformat = EOL_DOS;
4941 else
4942 sp->fileformat = EOL_UNIX;
4943 }
4944
4945 if (sp->fileformat == EOL_DOS)
4946 {
4947 if (has_cr) /* replace trailing CR */
4948 {
4949 buf[len - 2] = '\n';
4950 --len;
4951 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004952 }
4953 else /* lines like ":map xx yy^M" will have failed */
4954 {
4955 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004956 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01004957 msg_source(HL_ATTR(HLF_W));
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004958 emsg(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004959 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004960 sp->error = TRUE;
4961 sp->fileformat = EOL_UNIX;
4962 }
4963 }
4964#endif
4965 /* The '\n' is escaped if there is an odd number of ^V's just
4966 * before it, first set "c" just before the 'V's and then check
4967 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4968 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4969 ;
4970 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4971 {
4972 sourcing_lnum++;
4973 continue;
4974 }
4975
4976 buf[len - 1] = NUL; /* remove the NL */
4977 }
4978
4979 /*
4980 * Check for ^C here now and then, so recursive :so can be broken.
4981 */
4982 line_breakcheck();
4983 break;
4984 }
4985
4986 if (have_read)
4987 return (char_u *)ga.ga_data;
4988
4989 vim_free(ga.ga_data);
4990 return NULL;
4991}
4992
Bram Moolenaar05159a02005-02-26 23:04:13 +00004993#if defined(FEAT_PROFILE) || defined(PROTO)
4994/*
4995 * Called when starting to read a script line.
4996 * "sourcing_lnum" must be correct!
4997 * When skipping lines it may not actually be executed, but we won't find out
4998 * until later and we need to store the time now.
4999 */
5000 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005001script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00005002{
5003 scriptitem_T *si;
5004 sn_prl_T *pp;
5005
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02005006 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00005007 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02005008 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00005009 if (si->sn_prof_on && sourcing_lnum >= 1)
5010 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005011 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00005012 * here isn't counted. */
Bram Moolenaar67435d92017-10-19 21:04:37 +02005013 (void)ga_grow(&si->sn_prl_ga,
5014 (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00005015 si->sn_prl_idx = sourcing_lnum - 1;
5016 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
5017 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
5018 {
5019 /* Zero counters for a line that was not used before. */
5020 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
5021 pp->snp_count = 0;
5022 profile_zero(&pp->sn_prl_total);
5023 profile_zero(&pp->sn_prl_self);
5024 ++si->sn_prl_ga.ga_len;
5025 }
5026 si->sn_prl_execed = FALSE;
5027 profile_start(&si->sn_prl_start);
5028 profile_zero(&si->sn_prl_children);
5029 profile_get_wait(&si->sn_prl_wait);
5030 }
5031}
5032
5033/*
5034 * Called when actually executing a function line.
5035 */
5036 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005037script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00005038{
5039 scriptitem_T *si;
5040
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02005041 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00005042 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02005043 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00005044 if (si->sn_prof_on && si->sn_prl_idx >= 0)
5045 si->sn_prl_execed = TRUE;
5046}
5047
5048/*
Bram Moolenaar67435d92017-10-19 21:04:37 +02005049 * Called when done with a script line.
Bram Moolenaar05159a02005-02-26 23:04:13 +00005050 */
5051 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005052script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00005053{
5054 scriptitem_T *si;
5055 sn_prl_T *pp;
5056
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02005057 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00005058 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02005059 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00005060 if (si->sn_prof_on && si->sn_prl_idx >= 0
5061 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
5062 {
5063 if (si->sn_prl_execed)
5064 {
5065 pp = &PRL_ITEM(si, si->sn_prl_idx);
5066 ++pp->snp_count;
5067 profile_end(&si->sn_prl_start);
5068 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00005069 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00005070 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
5071 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00005072 }
5073 si->sn_prl_idx = -1;
5074 }
5075}
5076#endif
5077
Bram Moolenaar071d4272004-06-13 20:20:40 +00005078/*
5079 * ":scriptencoding": Set encoding conversion for a sourced script.
5080 * Without the multi-byte feature it's simply ignored.
5081 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005082 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005083ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005084{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005085 struct source_cookie *sp;
5086 char_u *name;
5087
5088 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
5089 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005090 emsg(_("E167: :scriptencoding used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005091 return;
5092 }
5093
5094 if (*eap->arg != NUL)
5095 {
5096 name = enc_canonize(eap->arg);
5097 if (name == NULL) /* out of memory */
5098 return;
5099 }
5100 else
5101 name = eap->arg;
5102
5103 /* Setup for conversion from the specified encoding to 'encoding'. */
5104 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
5105 convert_setup(&sp->conv, name, p_enc);
5106
5107 if (name != eap->arg)
5108 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005109}
5110
5111#if defined(FEAT_EVAL) || defined(PROTO)
5112/*
5113 * ":finish": Mark a sourced file as finished.
5114 */
5115 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005116ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005117{
5118 if (getline_equal(eap->getline, eap->cookie, getsourceline))
5119 do_finish(eap, FALSE);
5120 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005121 emsg(_("E168: :finish used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005122}
5123
5124/*
5125 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
5126 * Also called for a pending finish at the ":endtry" or after returning from
5127 * an extra do_cmdline(). "reanimate" is used in the latter case.
5128 */
5129 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005130do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005131{
5132 int idx;
5133
5134 if (reanimate)
5135 ((struct source_cookie *)getline_cookie(eap->getline,
5136 eap->cookie))->finished = FALSE;
5137
5138 /*
5139 * Cleanup (and inactivate) conditionals, but stop when a try conditional
5140 * not in its finally clause (which then is to be executed next) is found.
5141 * In this case, make the ":finish" pending for execution at the ":endtry".
5142 * Otherwise, finish normally.
5143 */
5144 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
5145 if (idx >= 0)
5146 {
5147 eap->cstack->cs_pending[idx] = CSTP_FINISH;
5148 report_make_pending(CSTP_FINISH, NULL);
5149 }
5150 else
5151 ((struct source_cookie *)getline_cookie(eap->getline,
5152 eap->cookie))->finished = TRUE;
5153}
5154
5155
5156/*
5157 * Return TRUE when a sourced file had the ":finish" command: Don't give error
5158 * message for missing ":endif".
5159 * Return FALSE when not sourcing a file.
5160 */
5161 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005162source_finished(
5163 char_u *(*fgetline)(int, void *, int),
5164 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005165{
Bram Moolenaar89d40322006-08-29 15:30:07 +00005166 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005167 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00005168 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005169}
5170#endif
5171
Bram Moolenaar071d4272004-06-13 20:20:40 +00005172/*
5173 * ":checktime [buffer]"
5174 */
5175 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005176ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005177{
5178 buf_T *buf;
5179 int save_no_check_timestamps = no_check_timestamps;
5180
5181 no_check_timestamps = 0;
5182 if (eap->addr_count == 0) /* default is all buffers */
5183 check_timestamps(FALSE);
5184 else
5185 {
5186 buf = buflist_findnr((int)eap->line2);
5187 if (buf != NULL) /* cannot happen? */
5188 (void)buf_check_timestamp(buf, FALSE);
5189 }
5190 no_check_timestamps = save_no_check_timestamps;
5191}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005192
Bram Moolenaar071d4272004-06-13 20:20:40 +00005193#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5194 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005195# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005196 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005197get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005198{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005199 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005200
Bram Moolenaar48e330a2016-02-23 14:53:34 +01005201 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005202 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005203
Bram Moolenaar4f974752019-02-17 17:44:42 +01005204# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00005205 if (loc != NULL)
5206 {
5207 char_u *p;
5208
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005209 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
5210 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005211 p = vim_strchr(loc, '=');
5212 if (p != NULL)
5213 {
5214 loc = ++p;
5215 while (*p != NUL) /* remove trailing newline */
5216 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005217 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00005218 {
5219 *p = NUL;
5220 break;
5221 }
5222 ++p;
5223 }
5224 }
5225 }
5226# endif
5227
5228 return loc;
5229}
5230#endif
5231
5232
Bram Moolenaar4f974752019-02-17 17:44:42 +01005233#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00005234/*
5235 * On MS-Windows locale names are strings like "German_Germany.1252", but
5236 * gettext expects "de". Try to translate one into another here for a few
5237 * supported languages.
5238 */
5239 static char_u *
5240gettext_lang(char_u *name)
5241{
5242 int i;
5243 static char *(mtable[]) = {
5244 "afrikaans", "af",
5245 "czech", "cs",
5246 "dutch", "nl",
5247 "german", "de",
5248 "english_united kingdom", "en_GB",
5249 "spanish", "es",
5250 "french", "fr",
5251 "italian", "it",
5252 "japanese", "ja",
5253 "korean", "ko",
5254 "norwegian", "no",
5255 "polish", "pl",
5256 "russian", "ru",
5257 "slovak", "sk",
5258 "swedish", "sv",
5259 "ukrainian", "uk",
5260 "chinese_china", "zh_CN",
5261 "chinese_taiwan", "zh_TW",
5262 NULL};
5263
5264 for (i = 0; mtable[i] != NULL; i += 2)
5265 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005266 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005267 return name;
5268}
5269#endif
5270
5271#if defined(FEAT_MULTI_LANG) || defined(PROTO)
5272/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01005273 * Return TRUE when "lang" starts with a valid language name.
5274 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
5275 */
5276 static int
5277is_valid_mess_lang(char_u *lang)
5278{
5279 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
5280}
5281
5282/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00005283 * Obtain the current messages language. Used to set the default for
5284 * 'helplang'. May return NULL or an empty string.
5285 */
5286 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005287get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005288{
5289 char_u *p;
5290
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005291# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005292# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005293 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005294# else
5295 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005296 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
5297 * and LC_MONETARY may be set differently for a Japanese working in the
5298 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005299 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005300# endif
5301# else
5302 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01005303 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005304 {
5305 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01005306 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005307 p = mch_getenv((char_u *)"LANG");
5308 }
5309# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005310# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00005311 p = gettext_lang(p);
5312# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01005313 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005314}
5315#endif
5316
Bram Moolenaardef9e822004-12-31 20:58:58 +00005317/* Complicated #if; matches with where get_mess_env() is used below. */
5318#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5319 && defined(LC_MESSAGES))) \
5320 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00005321 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005322/*
5323 * Get the language used for messages from the environment.
5324 */
5325 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005326get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005327{
5328 char_u *p;
5329
5330 p = mch_getenv((char_u *)"LC_ALL");
5331 if (p == NULL || *p == NUL)
5332 {
5333 p = mch_getenv((char_u *)"LC_MESSAGES");
5334 if (p == NULL || *p == NUL)
5335 {
5336 p = mch_getenv((char_u *)"LANG");
5337 if (p != NULL && VIM_ISDIGIT(*p))
5338 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005339# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005340 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005341 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005342# endif
5343 }
5344 }
5345 return p;
5346}
5347#endif
5348
5349#if defined(FEAT_EVAL) || defined(PROTO)
5350
5351/*
5352 * Set the "v:lang" variable according to the current locale setting.
5353 * Also do "v:lc_time"and "v:ctype".
5354 */
5355 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005356set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005357{
5358 char_u *loc;
5359
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005360# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005361 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005362# else
5363 /* setlocale() not supported: use the default value */
5364 loc = (char_u *)"C";
5365# endif
5366 set_vim_var_string(VV_CTYPE, loc, -1);
5367
5368 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
5369 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005370# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005371 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005372# else
5373 loc = get_mess_env();
5374# endif
5375 set_vim_var_string(VV_LANG, loc, -1);
5376
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005377# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005378 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005379# endif
5380 set_vim_var_string(VV_LC_TIME, loc, -1);
5381}
5382#endif
5383
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01005384#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00005385/*
5386 * ":language": Set the language (locale).
5387 */
5388 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005389ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005390{
5391 char *loc;
5392 char_u *p;
5393 char_u *name;
5394 int what = LC_ALL;
5395 char *whatstr = "";
5396#ifdef LC_MESSAGES
5397# define VIM_LC_MESSAGES LC_MESSAGES
5398#else
5399# define VIM_LC_MESSAGES 6789
5400#endif
5401
5402 name = eap->arg;
5403
5404 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
5405 * Allow abbreviation, but require at least 3 characters to avoid
5406 * confusion with a two letter language name "me" or "ct". */
5407 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01005408 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005409 {
5410 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
5411 {
5412 what = VIM_LC_MESSAGES;
5413 name = skipwhite(p);
5414 whatstr = "messages ";
5415 }
5416 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
5417 {
5418 what = LC_CTYPE;
5419 name = skipwhite(p);
5420 whatstr = "ctype ";
5421 }
5422 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
5423 {
5424 what = LC_TIME;
5425 name = skipwhite(p);
5426 whatstr = "time ";
5427 }
5428 }
5429
5430 if (*name == NUL)
5431 {
5432#ifndef LC_MESSAGES
5433 if (what == VIM_LC_MESSAGES)
5434 p = get_mess_env();
5435 else
5436#endif
5437 p = (char_u *)setlocale(what, NULL);
5438 if (p == NULL || *p == NUL)
5439 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005440 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005441 }
5442 else
5443 {
5444#ifndef LC_MESSAGES
5445 if (what == VIM_LC_MESSAGES)
5446 loc = "";
5447 else
5448#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005449 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005450 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005451#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
5452 /* Make sure strtod() uses a decimal point, not a comma. */
5453 setlocale(LC_NUMERIC, "C");
5454#endif
5455 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005456 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005457 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005458 else
5459 {
5460#ifdef HAVE_NL_MSG_CAT_CNTR
5461 /* Need to do this for GNU gettext, otherwise cached translations
5462 * will be used again. */
5463 extern int _nl_msg_cat_cntr;
5464
5465 ++_nl_msg_cat_cntr;
5466#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00005467 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005468 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
5469
5470 if (what != LC_TIME)
5471 {
5472 /* Tell gettext() what to translate to. It apparently doesn't
5473 * use the currently effective locale. Also do this when
5474 * FEAT_GETTEXT isn't defined, so that shell commands use this
5475 * value. */
5476 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005477 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005478 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02005479
5480 /* Clear $LANGUAGE because GNU gettext uses it. */
5481 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01005482# ifdef MSWIN
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005483 /* Apparently MS-Windows printf() may cause a crash when
5484 * we give it 8-bit text while it's expecting text in the
5485 * current locale. This call avoids that. */
5486 setlocale(LC_CTYPE, "C");
5487# endif
5488 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005489 if (what != LC_CTYPE)
5490 {
5491 char_u *mname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005492#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00005493 mname = gettext_lang(name);
5494#else
5495 mname = name;
5496#endif
5497 vim_setenv((char_u *)"LC_MESSAGES", mname);
5498#ifdef FEAT_MULTI_LANG
5499 set_helplang_default(mname);
5500#endif
5501 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005502 }
5503
5504# ifdef FEAT_EVAL
5505 /* Set v:lang, v:lc_time and v:ctype to the final result. */
5506 set_lang_var();
5507# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02005508# ifdef FEAT_TITLE
5509 maketitle();
5510# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005511 }
5512 }
5513}
5514
5515# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005516
5517static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01005518
Bram Moolenaar4f974752019-02-17 17:44:42 +01005519# ifndef MSWIN
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005520static int did_init_locales = FALSE;
5521
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005522/* Return an array of strings for all available locales + NULL for the
5523 * last element. Return NULL in case of error. */
5524 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005525find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005526{
5527 garray_T locales_ga;
5528 char_u *loc;
5529
5530 /* Find all available locales by running command "locale -a". If this
5531 * doesn't work we won't have completion. */
5532 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02005533 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005534 if (locale_a == NULL)
5535 return NULL;
5536 ga_init2(&locales_ga, sizeof(char_u *), 20);
5537
5538 /* Transform locale_a string where each locale is separated by "\n"
5539 * into an array of locale strings. */
5540 loc = (char_u *)strtok((char *)locale_a, "\n");
5541
5542 while (loc != NULL)
5543 {
5544 if (ga_grow(&locales_ga, 1) == FAIL)
5545 break;
5546 loc = vim_strsave(loc);
5547 if (loc == NULL)
5548 break;
5549
5550 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
5551 loc = (char_u *)strtok(NULL, "\n");
5552 }
5553 vim_free(locale_a);
5554 if (ga_grow(&locales_ga, 1) == FAIL)
5555 {
5556 ga_clear(&locales_ga);
5557 return NULL;
5558 }
5559 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
5560 return (char_u **)locales_ga.ga_data;
5561}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01005562# endif
5563
5564/*
5565 * Lazy initialization of all available locales.
5566 */
5567 static void
5568init_locales(void)
5569{
Bram Moolenaar4f974752019-02-17 17:44:42 +01005570# ifndef MSWIN
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01005571 if (!did_init_locales)
5572 {
5573 did_init_locales = TRUE;
5574 locales = find_locales();
5575 }
5576# endif
5577}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005578
5579# if defined(EXITFREE) || defined(PROTO)
5580 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005581free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005582{
5583 int i;
5584 if (locales != NULL)
5585 {
5586 for (i = 0; locales[i] != NULL; i++)
5587 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01005588 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005589 }
5590}
5591# endif
5592
Bram Moolenaar071d4272004-06-13 20:20:40 +00005593/*
5594 * Function given to ExpandGeneric() to obtain the possible arguments of the
5595 * ":language" command.
5596 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005597 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005598get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005599{
5600 if (idx == 0)
5601 return (char_u *)"messages";
5602 if (idx == 1)
5603 return (char_u *)"ctype";
5604 if (idx == 2)
5605 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005606
5607 init_locales();
5608 if (locales == NULL)
5609 return NULL;
5610 return locales[idx - 3];
5611}
5612
5613/*
5614 * Function given to ExpandGeneric() to obtain the available locales.
5615 */
5616 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005617get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005618{
5619 init_locales();
5620 if (locales == NULL)
5621 return NULL;
5622 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005623}
5624# endif
5625
5626#endif