blob: 57b5674e14d2295a19823384959b3be6a101af49 [file] [log] [blame]
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * autocmd.c: Autocommand related functions
12 */
13
14#include "vim.h"
15
16/*
17 * The autocommands are stored in a list for each event.
18 * Autocommands for the same pattern, that are consecutive, are joined
19 * together, to avoid having to match the pattern too often.
20 * The result is an array of Autopat lists, which point to AutoCmd lists:
21 *
22 * last_autopat[0] -----------------------------+
23 * V
24 * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
25 * Autopat.cmds Autopat.cmds
26 * | |
27 * V V
28 * AutoCmd.next AutoCmd.next
29 * | |
30 * V V
31 * AutoCmd.next NULL
32 * |
33 * V
34 * NULL
35 *
36 * last_autopat[1] --------+
37 * V
38 * first_autopat[1] --> Autopat.next --> NULL
39 * Autopat.cmds
40 * |
41 * V
42 * AutoCmd.next
43 * |
44 * V
45 * NULL
46 * etc.
47 *
48 * The order of AutoCmds is important, this is the order in which they were
49 * defined and will have to be executed.
50 */
51typedef struct AutoCmd
52{
53 char_u *cmd; // The command to be executed (NULL
54 // when command has been removed).
Bram Moolenaareb93f3f2019-04-04 15:04:56 +020055 char once; // "One shot": removed after execution
Bram Moolenaar3e460fd2019-01-26 16:21:07 +010056 char nested; // If autocommands nest here.
57 char last; // last command in list
58#ifdef FEAT_EVAL
59 sctx_T script_ctx; // script context where defined
60#endif
61 struct AutoCmd *next; // next AutoCmd in list
62} AutoCmd;
63
64typedef struct AutoPat
65{
66 struct AutoPat *next; // Next AutoPat in AutoPat list; MUST
67 // be the first entry.
68 char_u *pat; // pattern as typed (NULL when pattern
69 // has been removed)
70 regprog_T *reg_prog; // compiled regprog for pattern
71 AutoCmd *cmds; // list of commands to do
72 int group; // group ID
73 int patlen; // strlen() of pat
74 int buflocal_nr; // !=0 for buffer-local AutoPat
75 char allow_dirs; // Pattern may match whole path
76 char last; // last pattern for apply_autocmds()
77} AutoPat;
78
79static struct event_name
80{
81 char *name; // event name
82 event_T event; // event number
83} event_names[] =
84{
85 {"BufAdd", EVENT_BUFADD},
86 {"BufCreate", EVENT_BUFADD},
87 {"BufDelete", EVENT_BUFDELETE},
88 {"BufEnter", EVENT_BUFENTER},
89 {"BufFilePost", EVENT_BUFFILEPOST},
90 {"BufFilePre", EVENT_BUFFILEPRE},
91 {"BufHidden", EVENT_BUFHIDDEN},
92 {"BufLeave", EVENT_BUFLEAVE},
93 {"BufNew", EVENT_BUFNEW},
94 {"BufNewFile", EVENT_BUFNEWFILE},
95 {"BufRead", EVENT_BUFREADPOST},
96 {"BufReadCmd", EVENT_BUFREADCMD},
97 {"BufReadPost", EVENT_BUFREADPOST},
98 {"BufReadPre", EVENT_BUFREADPRE},
99 {"BufUnload", EVENT_BUFUNLOAD},
100 {"BufWinEnter", EVENT_BUFWINENTER},
101 {"BufWinLeave", EVENT_BUFWINLEAVE},
102 {"BufWipeout", EVENT_BUFWIPEOUT},
103 {"BufWrite", EVENT_BUFWRITEPRE},
104 {"BufWritePost", EVENT_BUFWRITEPOST},
105 {"BufWritePre", EVENT_BUFWRITEPRE},
106 {"BufWriteCmd", EVENT_BUFWRITECMD},
107 {"CmdlineChanged", EVENT_CMDLINECHANGED},
108 {"CmdlineEnter", EVENT_CMDLINEENTER},
109 {"CmdlineLeave", EVENT_CMDLINELEAVE},
110 {"CmdwinEnter", EVENT_CMDWINENTER},
111 {"CmdwinLeave", EVENT_CMDWINLEAVE},
112 {"CmdUndefined", EVENT_CMDUNDEFINED},
113 {"ColorScheme", EVENT_COLORSCHEME},
114 {"ColorSchemePre", EVENT_COLORSCHEMEPRE},
Bram Moolenaard7f246c2019-04-08 18:15:41 +0200115 {"CompleteChanged", EVENT_COMPLETECHANGED},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100116 {"CompleteDone", EVENT_COMPLETEDONE},
Bram Moolenaar3f169ce2020-01-26 22:43:31 +0100117 {"CompleteDonePre", EVENT_COMPLETEDONEPRE},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100118 {"CursorHold", EVENT_CURSORHOLD},
119 {"CursorHoldI", EVENT_CURSORHOLDI},
120 {"CursorMoved", EVENT_CURSORMOVED},
121 {"CursorMovedI", EVENT_CURSORMOVEDI},
122 {"DiffUpdated", EVENT_DIFFUPDATED},
123 {"DirChanged", EVENT_DIRCHANGED},
124 {"EncodingChanged", EVENT_ENCODINGCHANGED},
125 {"ExitPre", EVENT_EXITPRE},
126 {"FileEncoding", EVENT_ENCODINGCHANGED},
127 {"FileAppendPost", EVENT_FILEAPPENDPOST},
128 {"FileAppendPre", EVENT_FILEAPPENDPRE},
129 {"FileAppendCmd", EVENT_FILEAPPENDCMD},
130 {"FileChangedShell",EVENT_FILECHANGEDSHELL},
131 {"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
132 {"FileChangedRO", EVENT_FILECHANGEDRO},
133 {"FileReadPost", EVENT_FILEREADPOST},
134 {"FileReadPre", EVENT_FILEREADPRE},
135 {"FileReadCmd", EVENT_FILEREADCMD},
136 {"FileType", EVENT_FILETYPE},
137 {"FileWritePost", EVENT_FILEWRITEPOST},
138 {"FileWritePre", EVENT_FILEWRITEPRE},
139 {"FileWriteCmd", EVENT_FILEWRITECMD},
140 {"FilterReadPost", EVENT_FILTERREADPOST},
141 {"FilterReadPre", EVENT_FILTERREADPRE},
142 {"FilterWritePost", EVENT_FILTERWRITEPOST},
143 {"FilterWritePre", EVENT_FILTERWRITEPRE},
144 {"FocusGained", EVENT_FOCUSGAINED},
145 {"FocusLost", EVENT_FOCUSLOST},
146 {"FuncUndefined", EVENT_FUNCUNDEFINED},
147 {"GUIEnter", EVENT_GUIENTER},
148 {"GUIFailed", EVENT_GUIFAILED},
149 {"InsertChange", EVENT_INSERTCHANGE},
150 {"InsertEnter", EVENT_INSERTENTER},
151 {"InsertLeave", EVENT_INSERTLEAVE},
152 {"InsertCharPre", EVENT_INSERTCHARPRE},
153 {"MenuPopup", EVENT_MENUPOPUP},
154 {"OptionSet", EVENT_OPTIONSET},
155 {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
156 {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
157 {"QuitPre", EVENT_QUITPRE},
158 {"RemoteReply", EVENT_REMOTEREPLY},
Bram Moolenaar8aeec402019-09-15 23:02:04 +0200159 {"SafeState", EVENT_SAFESTATE},
Bram Moolenaar69198cb2019-09-16 21:58:13 +0200160 {"SafeStateAgain", EVENT_SAFESTATEAGAIN},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100161 {"SessionLoadPost", EVENT_SESSIONLOADPOST},
162 {"ShellCmdPost", EVENT_SHELLCMDPOST},
163 {"ShellFilterPost", EVENT_SHELLFILTERPOST},
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200164 {"SigUSR1", EVENT_SIGUSR1},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100165 {"SourceCmd", EVENT_SOURCECMD},
166 {"SourcePre", EVENT_SOURCEPRE},
167 {"SourcePost", EVENT_SOURCEPOST},
168 {"SpellFileMissing",EVENT_SPELLFILEMISSING},
169 {"StdinReadPost", EVENT_STDINREADPOST},
170 {"StdinReadPre", EVENT_STDINREADPRE},
171 {"SwapExists", EVENT_SWAPEXISTS},
172 {"Syntax", EVENT_SYNTAX},
173 {"TabNew", EVENT_TABNEW},
174 {"TabClosed", EVENT_TABCLOSED},
175 {"TabEnter", EVENT_TABENTER},
176 {"TabLeave", EVENT_TABLEAVE},
177 {"TermChanged", EVENT_TERMCHANGED},
178 {"TerminalOpen", EVENT_TERMINALOPEN},
Bram Moolenaar28ed4df2019-10-26 16:21:40 +0200179 {"TerminalWinOpen", EVENT_TERMINALWINOPEN},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100180 {"TermResponse", EVENT_TERMRESPONSE},
181 {"TextChanged", EVENT_TEXTCHANGED},
182 {"TextChangedI", EVENT_TEXTCHANGEDI},
183 {"TextChangedP", EVENT_TEXTCHANGEDP},
184 {"User", EVENT_USER},
185 {"VimEnter", EVENT_VIMENTER},
186 {"VimLeave", EVENT_VIMLEAVE},
187 {"VimLeavePre", EVENT_VIMLEAVEPRE},
188 {"WinNew", EVENT_WINNEW},
189 {"WinEnter", EVENT_WINENTER},
190 {"WinLeave", EVENT_WINLEAVE},
191 {"VimResized", EVENT_VIMRESIZED},
192 {"TextYankPost", EVENT_TEXTYANKPOST},
193 {NULL, (event_T)0}
194};
195
196static AutoPat *first_autopat[NUM_EVENTS] =
197{
198 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
199 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
200 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
201 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
202 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
203 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
204};
205
206static AutoPat *last_autopat[NUM_EVENTS] =
207{
208 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
209 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
210 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
211 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
212 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
213 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
214};
215
216#define AUGROUP_DEFAULT -1 // default autocmd group
217#define AUGROUP_ERROR -2 // erroneous autocmd group
218#define AUGROUP_ALL -3 // all autocmd groups
219
220/*
221 * struct used to keep status while executing autocommands for an event.
222 */
Bram Moolenaar1a47ae32019-12-29 23:04:25 +0100223struct AutoPatCmd_S
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100224{
225 AutoPat *curpat; // next AutoPat to examine
226 AutoCmd *nextcmd; // next AutoCmd to execute
227 int group; // group being used
228 char_u *fname; // fname to match with
229 char_u *sfname; // sfname to match with
230 char_u *tail; // tail of fname
231 event_T event; // current event
232 int arg_bufnr; // Initially equal to <abuf>, set to zero when
233 // buf is deleted.
Bram Moolenaar1a47ae32019-12-29 23:04:25 +0100234 AutoPatCmd *next; // chain of active apc-s for auto-invalidation
235};
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100236
Bram Moolenaarc667da52019-11-30 20:52:27 +0100237static AutoPatCmd *active_apc_list = NULL; // stack of active autocommands
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100238
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200239// Macro to loop over all the patterns for an autocmd event
240#define FOR_ALL_AUTOCMD_PATTERNS(event, ap) \
241 for ((ap) = first_autopat[(int)(event)]; (ap) != NULL; (ap) = (ap)->next)
242
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100243/*
244 * augroups stores a list of autocmd group names.
245 */
246static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
247#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
Bram Moolenaarc667da52019-11-30 20:52:27 +0100248// use get_deleted_augroup() to get this
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100249static char_u *deleted_augroup = NULL;
250
251/*
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100252 * The ID of the current group. Group 0 is the default one.
253 */
254static int current_augroup = AUGROUP_DEFAULT;
255
Bram Moolenaarc667da52019-11-30 20:52:27 +0100256static int au_need_clean = FALSE; // need to delete marked patterns
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100257
258static char_u *event_nr2name(event_T event);
259static int au_get_grouparg(char_u **argp);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200260static int do_autocmd_event(event_T event, char_u *pat, int once, int nested, char_u *cmd, int forceit, int group);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100261static int apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap);
262static void auto_next_pat(AutoPatCmd *apc, int stop_at_last);
263static int au_find_group(char_u *name);
264
265static event_T last_event;
266static int last_group;
Bram Moolenaarc667da52019-11-30 20:52:27 +0100267static int autocmd_blocked = 0; // block all autocmds
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100268
269 static char_u *
270get_deleted_augroup(void)
271{
272 if (deleted_augroup == NULL)
273 deleted_augroup = (char_u *)_("--Deleted--");
274 return deleted_augroup;
275}
276
277/*
278 * Show the autocommands for one AutoPat.
279 */
280 static void
281show_autocmd(AutoPat *ap, event_T event)
282{
283 AutoCmd *ac;
284
285 // Check for "got_int" (here and at various places below), which is set
286 // when "q" has been hit for the "--more--" prompt
287 if (got_int)
288 return;
289 if (ap->pat == NULL) // pattern has been removed
290 return;
291
292 msg_putchar('\n');
293 if (got_int)
294 return;
295 if (event != last_event || ap->group != last_group)
296 {
297 if (ap->group != AUGROUP_DEFAULT)
298 {
299 if (AUGROUP_NAME(ap->group) == NULL)
300 msg_puts_attr((char *)get_deleted_augroup(), HL_ATTR(HLF_E));
301 else
302 msg_puts_attr((char *)AUGROUP_NAME(ap->group), HL_ATTR(HLF_T));
303 msg_puts(" ");
304 }
305 msg_puts_attr((char *)event_nr2name(event), HL_ATTR(HLF_T));
306 last_event = event;
307 last_group = ap->group;
308 msg_putchar('\n');
309 if (got_int)
310 return;
311 }
312 msg_col = 4;
313 msg_outtrans(ap->pat);
314
315 for (ac = ap->cmds; ac != NULL; ac = ac->next)
316 {
317 if (ac->cmd != NULL) // skip removed commands
318 {
319 if (msg_col >= 14)
320 msg_putchar('\n');
321 msg_col = 14;
322 if (got_int)
323 return;
324 msg_outtrans(ac->cmd);
325#ifdef FEAT_EVAL
326 if (p_verbose > 0)
327 last_set_msg(ac->script_ctx);
328#endif
329 if (got_int)
330 return;
331 if (ac->next != NULL)
332 {
333 msg_putchar('\n');
334 if (got_int)
335 return;
336 }
337 }
338 }
339}
340
341/*
342 * Mark an autocommand pattern for deletion.
343 */
344 static void
345au_remove_pat(AutoPat *ap)
346{
347 VIM_CLEAR(ap->pat);
348 ap->buflocal_nr = -1;
349 au_need_clean = TRUE;
350}
351
352/*
353 * Mark all commands for a pattern for deletion.
354 */
355 static void
356au_remove_cmds(AutoPat *ap)
357{
358 AutoCmd *ac;
359
360 for (ac = ap->cmds; ac != NULL; ac = ac->next)
361 VIM_CLEAR(ac->cmd);
362 au_need_clean = TRUE;
363}
364
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200365// Delete one command from an autocmd pattern.
366static void au_del_cmd(AutoCmd *ac)
367{
368 VIM_CLEAR(ac->cmd);
369 au_need_clean = TRUE;
370}
371
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100372/*
373 * Cleanup autocommands and patterns that have been deleted.
374 * This is only done when not executing autocommands.
375 */
376 static void
377au_cleanup(void)
378{
379 AutoPat *ap, **prev_ap;
380 AutoCmd *ac, **prev_ac;
381 event_T event;
382
383 if (autocmd_busy || !au_need_clean)
384 return;
385
386 // loop over all events
387 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
388 event = (event_T)((int)event + 1))
389 {
390 // loop over all autocommand patterns
391 prev_ap = &(first_autopat[(int)event]);
392 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
393 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200394 int has_cmd = FALSE;
395
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200396 // loop over all commands for this pattern
397 prev_ac = &(ap->cmds);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100398 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
399 {
400 // remove the command if the pattern is to be deleted or when
401 // the command has been marked for deletion
402 if (ap->pat == NULL || ac->cmd == NULL)
403 {
404 *prev_ac = ac->next;
405 vim_free(ac->cmd);
406 vim_free(ac);
407 }
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200408 else
409 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200410 has_cmd = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100411 prev_ac = &(ac->next);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200412 }
413 }
414
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200415 if (ap->pat != NULL && !has_cmd)
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200416 // Pattern was not marked for deletion, but all of its
417 // commands were. So mark the pattern for deletion.
418 au_remove_pat(ap);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100419
420 // remove the pattern if it has been marked for deletion
421 if (ap->pat == NULL)
422 {
423 if (ap->next == NULL)
424 {
425 if (prev_ap == &(first_autopat[(int)event]))
426 last_autopat[(int)event] = NULL;
427 else
428 // this depends on the "next" field being the first in
429 // the struct
430 last_autopat[(int)event] = (AutoPat *)prev_ap;
431 }
432 *prev_ap = ap->next;
433 vim_regfree(ap->reg_prog);
434 vim_free(ap);
435 }
436 else
437 prev_ap = &(ap->next);
438 }
439 }
440
441 au_need_clean = FALSE;
442}
443
444/*
445 * Called when buffer is freed, to remove/invalidate related buffer-local
446 * autocmds.
447 */
448 void
449aubuflocal_remove(buf_T *buf)
450{
451 AutoPat *ap;
452 event_T event;
453 AutoPatCmd *apc;
454
455 // invalidate currently executing autocommands
456 for (apc = active_apc_list; apc; apc = apc->next)
457 if (buf->b_fnum == apc->arg_bufnr)
458 apc->arg_bufnr = 0;
459
460 // invalidate buflocals looping through events
461 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
462 event = (event_T)((int)event + 1))
463 // loop over all autocommand patterns
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200464 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100465 if (ap->buflocal_nr == buf->b_fnum)
466 {
467 au_remove_pat(ap);
468 if (p_verbose >= 6)
469 {
470 verbose_enter();
471 smsg(_("auto-removing autocommand: %s <buffer=%d>"),
472 event_nr2name(event), buf->b_fnum);
473 verbose_leave();
474 }
475 }
476 au_cleanup();
477}
478
479/*
480 * Add an autocmd group name.
481 * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
482 */
483 static int
484au_new_group(char_u *name)
485{
486 int i;
487
488 i = au_find_group(name);
489 if (i == AUGROUP_ERROR) // the group doesn't exist yet, add it
490 {
491 // First try using a free entry.
492 for (i = 0; i < augroups.ga_len; ++i)
493 if (AUGROUP_NAME(i) == NULL)
494 break;
495 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
496 return AUGROUP_ERROR;
497
498 AUGROUP_NAME(i) = vim_strsave(name);
499 if (AUGROUP_NAME(i) == NULL)
500 return AUGROUP_ERROR;
501 if (i == augroups.ga_len)
502 ++augroups.ga_len;
503 }
504
505 return i;
506}
507
508 static void
509au_del_group(char_u *name)
510{
511 int i;
512
513 i = au_find_group(name);
514 if (i == AUGROUP_ERROR) // the group doesn't exist
515 semsg(_("E367: No such group: \"%s\""), name);
516 else if (i == current_augroup)
517 emsg(_("E936: Cannot delete the current group"));
518 else
519 {
520 event_T event;
521 AutoPat *ap;
522 int in_use = FALSE;
523
524 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
525 event = (event_T)((int)event + 1))
526 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200527 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100528 if (ap->group == i && ap->pat != NULL)
529 {
530 give_warning((char_u *)_("W19: Deleting augroup that is still in use"), TRUE);
531 in_use = TRUE;
532 event = NUM_EVENTS;
533 break;
534 }
535 }
536 vim_free(AUGROUP_NAME(i));
537 if (in_use)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100538 AUGROUP_NAME(i) = get_deleted_augroup();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100539 else
540 AUGROUP_NAME(i) = NULL;
541 }
542}
543
544/*
545 * Find the ID of an autocmd group name.
546 * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
547 */
548 static int
549au_find_group(char_u *name)
550{
551 int i;
552
553 for (i = 0; i < augroups.ga_len; ++i)
554 if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup()
555 && STRCMP(AUGROUP_NAME(i), name) == 0)
556 return i;
557 return AUGROUP_ERROR;
558}
559
560/*
561 * Return TRUE if augroup "name" exists.
562 */
563 int
564au_has_group(char_u *name)
565{
566 return au_find_group(name) != AUGROUP_ERROR;
567}
568
569/*
570 * ":augroup {name}".
571 */
572 void
573do_augroup(char_u *arg, int del_group)
574{
575 int i;
576
577 if (del_group)
578 {
579 if (*arg == NUL)
580 emsg(_(e_argreq));
581 else
582 au_del_group(arg);
583 }
584 else if (STRICMP(arg, "end") == 0) // ":aug end": back to group 0
585 current_augroup = AUGROUP_DEFAULT;
586 else if (*arg) // ":aug xxx": switch to group xxx
587 {
588 i = au_new_group(arg);
589 if (i != AUGROUP_ERROR)
590 current_augroup = i;
591 }
592 else // ":aug": list the group names
593 {
594 msg_start();
595 for (i = 0; i < augroups.ga_len; ++i)
596 {
597 if (AUGROUP_NAME(i) != NULL)
598 {
599 msg_puts((char *)AUGROUP_NAME(i));
600 msg_puts(" ");
601 }
602 }
603 msg_clr_eos();
604 msg_end();
605 }
606}
607
608#if defined(EXITFREE) || defined(PROTO)
609 void
610free_all_autocmds(void)
611{
612 int i;
613 char_u *s;
614
615 for (current_augroup = -1; current_augroup < augroups.ga_len;
616 ++current_augroup)
617 do_autocmd((char_u *)"", TRUE);
618
619 for (i = 0; i < augroups.ga_len; ++i)
620 {
621 s = ((char_u **)(augroups.ga_data))[i];
622 if (s != get_deleted_augroup())
623 vim_free(s);
624 }
625 ga_clear(&augroups);
626}
627#endif
628
629/*
630 * Return the event number for event name "start".
631 * Return NUM_EVENTS if the event name was not found.
632 * Return a pointer to the next event name in "end".
633 */
634 static event_T
635event_name2nr(char_u *start, char_u **end)
636{
637 char_u *p;
638 int i;
639 int len;
640
641 // the event name ends with end of line, '|', a blank or a comma
642 for (p = start; *p && !VIM_ISWHITE(*p) && *p != ',' && *p != '|'; ++p)
643 ;
644 for (i = 0; event_names[i].name != NULL; ++i)
645 {
646 len = (int)STRLEN(event_names[i].name);
647 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
648 break;
649 }
650 if (*p == ',')
651 ++p;
652 *end = p;
653 if (event_names[i].name == NULL)
654 return NUM_EVENTS;
655 return event_names[i].event;
656}
657
658/*
659 * Return the name for event "event".
660 */
661 static char_u *
662event_nr2name(event_T event)
663{
664 int i;
665
666 for (i = 0; event_names[i].name != NULL; ++i)
667 if (event_names[i].event == event)
668 return (char_u *)event_names[i].name;
669 return (char_u *)"Unknown";
670}
671
672/*
673 * Scan over the events. "*" stands for all events.
674 */
675 static char_u *
676find_end_event(
677 char_u *arg,
678 int have_group) // TRUE when group name was found
679{
680 char_u *pat;
681 char_u *p;
682
683 if (*arg == '*')
684 {
685 if (arg[1] && !VIM_ISWHITE(arg[1]))
686 {
687 semsg(_("E215: Illegal character after *: %s"), arg);
688 return NULL;
689 }
690 pat = arg + 1;
691 }
692 else
693 {
694 for (pat = arg; *pat && *pat != '|' && !VIM_ISWHITE(*pat); pat = p)
695 {
696 if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
697 {
698 if (have_group)
699 semsg(_("E216: No such event: %s"), pat);
700 else
701 semsg(_("E216: No such group or event: %s"), pat);
702 return NULL;
703 }
704 }
705 }
706 return pat;
707}
708
709/*
710 * Return TRUE if "event" is included in 'eventignore'.
711 */
712 static int
713event_ignored(event_T event)
714{
715 char_u *p = p_ei;
716
717 while (*p != NUL)
718 {
719 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
720 return TRUE;
721 if (event_name2nr(p, &p) == event)
722 return TRUE;
723 }
724
725 return FALSE;
726}
727
728/*
729 * Return OK when the contents of p_ei is valid, FAIL otherwise.
730 */
731 int
732check_ei(void)
733{
734 char_u *p = p_ei;
735
736 while (*p)
737 {
738 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
739 {
740 p += 3;
741 if (*p == ',')
742 ++p;
743 }
744 else if (event_name2nr(p, &p) == NUM_EVENTS)
745 return FAIL;
746 }
747
748 return OK;
749}
750
751# if defined(FEAT_SYN_HL) || defined(PROTO)
752
753/*
754 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
755 * buffer loaded into the window. "what" must start with a comma.
756 * Returns the old value of 'eventignore' in allocated memory.
757 */
758 char_u *
759au_event_disable(char *what)
760{
761 char_u *new_ei;
762 char_u *save_ei;
763
764 save_ei = vim_strsave(p_ei);
765 if (save_ei != NULL)
766 {
Bram Moolenaardf44a272020-06-07 20:49:05 +0200767 new_ei = vim_strnsave(p_ei, STRLEN(p_ei) + STRLEN(what));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100768 if (new_ei != NULL)
769 {
770 if (*what == ',' && *p_ei == NUL)
771 STRCPY(new_ei, what + 1);
772 else
773 STRCAT(new_ei, what);
774 set_string_option_direct((char_u *)"ei", -1, new_ei,
775 OPT_FREE, SID_NONE);
776 vim_free(new_ei);
777 }
778 }
779 return save_ei;
780}
781
782 void
783au_event_restore(char_u *old_ei)
784{
785 if (old_ei != NULL)
786 {
787 set_string_option_direct((char_u *)"ei", -1, old_ei,
788 OPT_FREE, SID_NONE);
789 vim_free(old_ei);
790 }
791}
Bram Moolenaarc667da52019-11-30 20:52:27 +0100792# endif // FEAT_SYN_HL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100793
794/*
795 * do_autocmd() -- implements the :autocmd command. Can be used in the
796 * following ways:
797 *
798 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
799 * will be automatically executed for <event>
800 * when editing a file matching <pat>, in
801 * the current group.
802 * :autocmd <event> <pat> Show the autocommands associated with
803 * <event> and <pat>.
804 * :autocmd <event> Show the autocommands associated with
805 * <event>.
806 * :autocmd Show all autocommands.
807 * :autocmd! <event> <pat> <cmd> Remove all autocommands associated with
808 * <event> and <pat>, and add the command
809 * <cmd>, for the current group.
810 * :autocmd! <event> <pat> Remove all autocommands associated with
811 * <event> and <pat> for the current group.
812 * :autocmd! <event> Remove all autocommands associated with
813 * <event> for the current group.
814 * :autocmd! Remove ALL autocommands for the current
815 * group.
816 *
817 * Multiple events and patterns may be given separated by commas. Here are
818 * some examples:
819 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
820 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
821 *
822 * :autocmd * *.c show all autocommands for *.c files.
823 *
824 * Mostly a {group} argument can optionally appear before <event>.
825 */
826 void
827do_autocmd(char_u *arg_in, int forceit)
828{
829 char_u *arg = arg_in;
830 char_u *pat;
831 char_u *envpat = NULL;
832 char_u *cmd;
833 event_T event;
834 int need_free = FALSE;
835 int nested = FALSE;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200836 int once = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100837 int group;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200838 int i;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100839
840 if (*arg == '|')
841 {
842 arg = (char_u *)"";
843 group = AUGROUP_ALL; // no argument, use all groups
844 }
845 else
846 {
847 /*
848 * Check for a legal group name. If not, use AUGROUP_ALL.
849 */
850 group = au_get_grouparg(&arg);
851 if (arg == NULL) // out of memory
852 return;
853 }
854
855 /*
856 * Scan over the events.
857 * If we find an illegal name, return here, don't do anything.
858 */
859 pat = find_end_event(arg, group != AUGROUP_ALL);
860 if (pat == NULL)
861 return;
862
863 pat = skipwhite(pat);
864 if (*pat == '|')
865 {
866 pat = (char_u *)"";
867 cmd = (char_u *)"";
868 }
869 else
870 {
871 /*
872 * Scan over the pattern. Put a NUL at the end.
873 */
874 cmd = pat;
875 while (*cmd && (!VIM_ISWHITE(*cmd) || cmd[-1] == '\\'))
876 cmd++;
877 if (*cmd)
878 *cmd++ = NUL;
879
880 // Expand environment variables in the pattern. Set 'shellslash', we
881 // want forward slashes here.
882 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
883 {
884#ifdef BACKSLASH_IN_FILENAME
885 int p_ssl_save = p_ssl;
886
887 p_ssl = TRUE;
888#endif
889 envpat = expand_env_save(pat);
890#ifdef BACKSLASH_IN_FILENAME
891 p_ssl = p_ssl_save;
892#endif
893 if (envpat != NULL)
894 pat = envpat;
895 }
896
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100897 cmd = skipwhite(cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200898 for (i = 0; i < 2; i++)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100899 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200900 if (*cmd != NUL)
901 {
902 // Check for "++once" flag.
903 if (STRNCMP(cmd, "++once", 6) == 0 && VIM_ISWHITE(cmd[6]))
904 {
905 if (once)
906 semsg(_(e_duparg2), "++once");
907 once = TRUE;
908 cmd = skipwhite(cmd + 6);
909 }
910
911 // Check for "++nested" flag.
912 if ((STRNCMP(cmd, "++nested", 8) == 0 && VIM_ISWHITE(cmd[8])))
913 {
914 if (nested)
915 semsg(_(e_duparg2), "++nested");
916 nested = TRUE;
917 cmd = skipwhite(cmd + 8);
918 }
919
920 // Check for the old "nested" flag.
921 if (STRNCMP(cmd, "nested", 6) == 0 && VIM_ISWHITE(cmd[6]))
922 {
923 if (nested)
924 semsg(_(e_duparg2), "nested");
925 nested = TRUE;
926 cmd = skipwhite(cmd + 6);
927 }
928 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100929 }
930
931 /*
932 * Find the start of the commands.
933 * Expand <sfile> in it.
934 */
935 if (*cmd != NUL)
936 {
937 cmd = expand_sfile(cmd);
938 if (cmd == NULL) // some error
939 return;
940 need_free = TRUE;
941 }
942 }
943
944 /*
945 * Print header when showing autocommands.
946 */
947 if (!forceit && *cmd == NUL)
948 // Highlight title
949 msg_puts_title(_("\n--- Autocommands ---"));
950
951 /*
952 * Loop over the events.
953 */
954 last_event = (event_T)-1; // for listing the event name
955 last_group = AUGROUP_ERROR; // for listing the group name
956 if (*arg == '*' || *arg == NUL || *arg == '|')
957 {
958 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
959 event = (event_T)((int)event + 1))
960 if (do_autocmd_event(event, pat,
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200961 once, nested, cmd, forceit, group) == FAIL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100962 break;
963 }
964 else
965 {
966 while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
967 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200968 once, nested, cmd, forceit, group) == FAIL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100969 break;
970 }
971
972 if (need_free)
973 vim_free(cmd);
974 vim_free(envpat);
975}
976
977/*
978 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
979 * The "argp" argument is advanced to the following argument.
980 *
981 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
982 */
983 static int
984au_get_grouparg(char_u **argp)
985{
986 char_u *group_name;
987 char_u *p;
988 char_u *arg = *argp;
989 int group = AUGROUP_ALL;
990
991 for (p = arg; *p && !VIM_ISWHITE(*p) && *p != '|'; ++p)
992 ;
993 if (p > arg)
994 {
Bram Moolenaardf44a272020-06-07 20:49:05 +0200995 group_name = vim_strnsave(arg, p - arg);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100996 if (group_name == NULL) // out of memory
997 return AUGROUP_ERROR;
998 group = au_find_group(group_name);
999 if (group == AUGROUP_ERROR)
1000 group = AUGROUP_ALL; // no match, use all groups
1001 else
1002 *argp = skipwhite(p); // match, skip over group name
1003 vim_free(group_name);
1004 }
1005 return group;
1006}
1007
1008/*
1009 * do_autocmd() for one event.
1010 * If *pat == NUL do for all patterns.
1011 * If *cmd == NUL show entries.
1012 * If forceit == TRUE delete entries.
1013 * If group is not AUGROUP_ALL, only use this group.
1014 */
1015 static int
1016do_autocmd_event(
1017 event_T event,
1018 char_u *pat,
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001019 int once,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001020 int nested,
1021 char_u *cmd,
1022 int forceit,
1023 int group)
1024{
1025 AutoPat *ap;
1026 AutoPat **prev_ap;
1027 AutoCmd *ac;
1028 AutoCmd **prev_ac;
1029 int brace_level;
1030 char_u *endpat;
1031 int findgroup;
1032 int allgroups;
1033 int patlen;
1034 int is_buflocal;
1035 int buflocal_nr;
Bram Moolenaarc667da52019-11-30 20:52:27 +01001036 char_u buflocal_pat[25]; // for "<buffer=X>"
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001037
1038 if (group == AUGROUP_ALL)
1039 findgroup = current_augroup;
1040 else
1041 findgroup = group;
1042 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
1043
1044 /*
1045 * Show or delete all patterns for an event.
1046 */
1047 if (*pat == NUL)
1048 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +02001049 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001050 {
1051 if (forceit) // delete the AutoPat, if it's in the current group
1052 {
1053 if (ap->group == findgroup)
1054 au_remove_pat(ap);
1055 }
1056 else if (group == AUGROUP_ALL || ap->group == group)
1057 show_autocmd(ap, event);
1058 }
1059 }
1060
1061 /*
1062 * Loop through all the specified patterns.
1063 */
1064 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
1065 {
1066 /*
1067 * Find end of the pattern.
1068 * Watch out for a comma in braces, like "*.\{obj,o\}".
1069 */
1070 brace_level = 0;
1071 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
1072 || (endpat > pat && endpat[-1] == '\\')); ++endpat)
1073 {
1074 if (*endpat == '{')
1075 brace_level++;
1076 else if (*endpat == '}')
1077 brace_level--;
1078 }
1079 if (pat == endpat) // ignore single comma
1080 continue;
1081 patlen = (int)(endpat - pat);
1082
1083 /*
1084 * detect special <buflocal[=X]> buffer-local patterns
1085 */
1086 is_buflocal = FALSE;
1087 buflocal_nr = 0;
1088
1089 if (patlen >= 8 && STRNCMP(pat, "<buffer", 7) == 0
1090 && pat[patlen - 1] == '>')
1091 {
1092 // "<buffer...>": Error will be printed only for addition.
1093 // printing and removing will proceed silently.
1094 is_buflocal = TRUE;
1095 if (patlen == 8)
1096 // "<buffer>"
1097 buflocal_nr = curbuf->b_fnum;
1098 else if (patlen > 9 && pat[7] == '=')
1099 {
1100 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13) == 0)
1101 // "<buffer=abuf>"
1102 buflocal_nr = autocmd_bufnr;
1103 else if (skipdigits(pat + 8) == pat + patlen - 1)
1104 // "<buffer=123>"
1105 buflocal_nr = atoi((char *)pat + 8);
1106 }
1107 }
1108
1109 if (is_buflocal)
1110 {
1111 // normalize pat into standard "<buffer>#N" form
1112 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
1113 pat = buflocal_pat; // can modify pat and patlen
1114 patlen = (int)STRLEN(buflocal_pat); // but not endpat
1115 }
1116
1117 /*
1118 * Find AutoPat entries with this pattern. When adding a command it
1119 * always goes at or after the last one, so start at the end.
1120 */
1121 if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL)
1122 prev_ap = &last_autopat[(int)event];
1123 else
1124 prev_ap = &first_autopat[(int)event];
1125 while ((ap = *prev_ap) != NULL)
1126 {
1127 if (ap->pat != NULL)
1128 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001129 /*
1130 * Accept a pattern when:
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001131 * - a group was specified and it's that group, or a group was
1132 * not specified and it's the current group, or a group was
1133 * not specified and we are listing
1134 * - the length of the pattern matches
1135 * - the pattern matches.
1136 * For <buffer[=X]>, this condition works because we normalize
1137 * all buffer-local patterns.
1138 */
1139 if ((allgroups || ap->group == findgroup)
1140 && ap->patlen == patlen
1141 && STRNCMP(pat, ap->pat, patlen) == 0)
1142 {
1143 /*
1144 * Remove existing autocommands.
1145 * If adding any new autocmd's for this AutoPat, don't
1146 * delete the pattern from the autopat list, append to
1147 * this list.
1148 */
1149 if (forceit)
1150 {
1151 if (*cmd != NUL && ap->next == NULL)
1152 {
1153 au_remove_cmds(ap);
1154 break;
1155 }
1156 au_remove_pat(ap);
1157 }
1158
1159 /*
1160 * Show autocmd's for this autopat, or buflocals <buffer=X>
1161 */
1162 else if (*cmd == NUL)
1163 show_autocmd(ap, event);
1164
1165 /*
1166 * Add autocmd to this autopat, if it's the last one.
1167 */
1168 else if (ap->next == NULL)
1169 break;
1170 }
1171 }
1172 prev_ap = &ap->next;
1173 }
1174
1175 /*
1176 * Add a new command.
1177 */
1178 if (*cmd != NUL)
1179 {
1180 /*
1181 * If the pattern we want to add a command to does appear at the
1182 * end of the list (or not is not in the list at all), add the
1183 * pattern at the end of the list.
1184 */
1185 if (ap == NULL)
1186 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001187 // refuse to add buffer-local ap if buffer number is invalid
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001188 if (is_buflocal && (buflocal_nr == 0
1189 || buflist_findnr(buflocal_nr) == NULL))
1190 {
1191 semsg(_("E680: <buffer=%d>: invalid buffer number "),
1192 buflocal_nr);
1193 return FAIL;
1194 }
1195
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001196 ap = ALLOC_ONE(AutoPat);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001197 if (ap == NULL)
1198 return FAIL;
1199 ap->pat = vim_strnsave(pat, patlen);
1200 ap->patlen = patlen;
1201 if (ap->pat == NULL)
1202 {
1203 vim_free(ap);
1204 return FAIL;
1205 }
1206
1207 if (is_buflocal)
1208 {
1209 ap->buflocal_nr = buflocal_nr;
1210 ap->reg_prog = NULL;
1211 }
1212 else
1213 {
1214 char_u *reg_pat;
1215
1216 ap->buflocal_nr = 0;
1217 reg_pat = file_pat_to_reg_pat(pat, endpat,
1218 &ap->allow_dirs, TRUE);
1219 if (reg_pat != NULL)
1220 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
1221 vim_free(reg_pat);
1222 if (reg_pat == NULL || ap->reg_prog == NULL)
1223 {
1224 vim_free(ap->pat);
1225 vim_free(ap);
1226 return FAIL;
1227 }
1228 }
1229 ap->cmds = NULL;
1230 *prev_ap = ap;
1231 last_autopat[(int)event] = ap;
1232 ap->next = NULL;
1233 if (group == AUGROUP_ALL)
1234 ap->group = current_augroup;
1235 else
1236 ap->group = group;
1237 }
1238
1239 /*
1240 * Add the autocmd at the end of the AutoCmd list.
1241 */
1242 prev_ac = &(ap->cmds);
1243 while ((ac = *prev_ac) != NULL)
1244 prev_ac = &ac->next;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001245 ac = ALLOC_ONE(AutoCmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001246 if (ac == NULL)
1247 return FAIL;
1248 ac->cmd = vim_strsave(cmd);
1249#ifdef FEAT_EVAL
1250 ac->script_ctx = current_sctx;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01001251 ac->script_ctx.sc_lnum += SOURCING_LNUM;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001252#endif
1253 if (ac->cmd == NULL)
1254 {
1255 vim_free(ac);
1256 return FAIL;
1257 }
1258 ac->next = NULL;
1259 *prev_ac = ac;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001260 ac->once = once;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001261 ac->nested = nested;
1262 }
1263 }
1264
1265 au_cleanup(); // may really delete removed patterns/commands now
1266 return OK;
1267}
1268
1269/*
1270 * Implementation of ":doautocmd [group] event [fname]".
1271 * Return OK for success, FAIL for failure;
1272 */
1273 int
1274do_doautocmd(
1275 char_u *arg,
1276 int do_msg, // give message for no matching autocmds?
1277 int *did_something)
1278{
1279 char_u *fname;
1280 int nothing_done = TRUE;
1281 int group;
1282
1283 if (did_something != NULL)
1284 *did_something = FALSE;
1285
1286 /*
1287 * Check for a legal group name. If not, use AUGROUP_ALL.
1288 */
1289 group = au_get_grouparg(&arg);
1290 if (arg == NULL) // out of memory
1291 return FAIL;
1292
1293 if (*arg == '*')
1294 {
1295 emsg(_("E217: Can't execute autocommands for ALL events"));
1296 return FAIL;
1297 }
1298
1299 /*
1300 * Scan over the events.
1301 * If we find an illegal name, return here, don't do anything.
1302 */
1303 fname = find_end_event(arg, group != AUGROUP_ALL);
1304 if (fname == NULL)
1305 return FAIL;
1306
1307 fname = skipwhite(fname);
1308
1309 /*
1310 * Loop over the events.
1311 */
1312 while (*arg && !ends_excmd(*arg) && !VIM_ISWHITE(*arg))
1313 if (apply_autocmds_group(event_name2nr(arg, &arg),
1314 fname, NULL, TRUE, group, curbuf, NULL))
1315 nothing_done = FALSE;
1316
1317 if (nothing_done && do_msg)
1318 msg(_("No matching autocommands"));
1319 if (did_something != NULL)
1320 *did_something = !nothing_done;
1321
1322#ifdef FEAT_EVAL
1323 return aborting() ? FAIL : OK;
1324#else
1325 return OK;
1326#endif
1327}
1328
1329/*
1330 * ":doautoall": execute autocommands for each loaded buffer.
1331 */
1332 void
1333ex_doautoall(exarg_T *eap)
1334{
1335 int retval;
1336 aco_save_T aco;
1337 buf_T *buf;
1338 bufref_T bufref;
1339 char_u *arg = eap->arg;
1340 int call_do_modelines = check_nomodeline(&arg);
1341 int did_aucmd;
1342
1343 /*
1344 * This is a bit tricky: For some commands curwin->w_buffer needs to be
1345 * equal to curbuf, but for some buffers there may not be a window.
1346 * So we change the buffer for the current window for a moment. This
1347 * gives problems when the autocommands make changes to the list of
1348 * buffers or windows...
1349 */
1350 FOR_ALL_BUFFERS(buf)
1351 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02001352 if (buf->b_ml.ml_mfp != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001353 {
1354 // find a window for this buffer and save some values
1355 aucmd_prepbuf(&aco, buf);
1356 set_bufref(&bufref, buf);
1357
1358 // execute the autocommands for this buffer
1359 retval = do_doautocmd(arg, FALSE, &did_aucmd);
1360
1361 if (call_do_modelines && did_aucmd)
1362 {
1363 // Execute the modeline settings, but don't set window-local
1364 // options if we are using the current window for another
1365 // buffer.
1366 do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
1367 }
1368
1369 // restore the current window
1370 aucmd_restbuf(&aco);
1371
1372 // stop if there is some error or buffer was deleted
1373 if (retval == FAIL || !bufref_valid(&bufref))
1374 break;
1375 }
1376 }
1377
1378 check_cursor(); // just in case lines got deleted
1379}
1380
1381/*
1382 * Check *argp for <nomodeline>. When it is present return FALSE, otherwise
1383 * return TRUE and advance *argp to after it.
1384 * Thus return TRUE when do_modelines() should be called.
1385 */
1386 int
1387check_nomodeline(char_u **argp)
1388{
1389 if (STRNCMP(*argp, "<nomodeline>", 12) == 0)
1390 {
1391 *argp = skipwhite(*argp + 12);
1392 return FALSE;
1393 }
1394 return TRUE;
1395}
1396
1397/*
1398 * Prepare for executing autocommands for (hidden) buffer "buf".
1399 * Search for a visible window containing the current buffer. If there isn't
1400 * one then use "aucmd_win".
1401 * Set "curbuf" and "curwin" to match "buf".
1402 */
1403 void
1404aucmd_prepbuf(
1405 aco_save_T *aco, // structure to save values in
1406 buf_T *buf) // new curbuf
1407{
1408 win_T *win;
1409 int save_ea;
1410#ifdef FEAT_AUTOCHDIR
1411 int save_acd;
1412#endif
1413
1414 // Find a window that is for the new buffer
1415 if (buf == curbuf) // be quick when buf is curbuf
1416 win = curwin;
1417 else
1418 FOR_ALL_WINDOWS(win)
1419 if (win->w_buffer == buf)
1420 break;
1421
1422 // Allocate "aucmd_win" when needed. If this fails (out of memory) fall
1423 // back to using the current window.
1424 if (win == NULL && aucmd_win == NULL)
1425 {
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001426 aucmd_win = win_alloc_popup_win();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001427 if (aucmd_win == NULL)
1428 win = curwin;
1429 }
1430 if (win == NULL && aucmd_win_used)
1431 // Strange recursive autocommand, fall back to using the current
1432 // window. Expect a few side effects...
1433 win = curwin;
1434
1435 aco->save_curwin = curwin;
1436 aco->save_curbuf = curbuf;
1437 aco->save_prevwin = prevwin;
1438 if (win != NULL)
1439 {
1440 // There is a window for "buf" in the current tab page, make it the
1441 // curwin. This is preferred, it has the least side effects (esp. if
1442 // "buf" is curbuf).
1443 aco->use_aucmd_win = FALSE;
1444 curwin = win;
1445 }
1446 else
1447 {
1448 // There is no window for "buf", use "aucmd_win". To minimize the side
1449 // effects, insert it in the current tab page.
1450 // Anything related to a window (e.g., setting folds) may have
1451 // unexpected results.
1452 aco->use_aucmd_win = TRUE;
1453 aucmd_win_used = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001454
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001455 win_init_popup_win(aucmd_win, buf);
1456
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001457 aco->globaldir = globaldir;
1458 globaldir = NULL;
1459
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001460 // Split the current window, put the aucmd_win in the upper half.
1461 // We don't want the BufEnter or WinEnter autocommands.
1462 block_autocmds();
1463 make_snapshot(SNAP_AUCMD_IDX);
1464 save_ea = p_ea;
1465 p_ea = FALSE;
1466
1467#ifdef FEAT_AUTOCHDIR
1468 // Prevent chdir() call in win_enter_ext(), through do_autochdir().
1469 save_acd = p_acd;
1470 p_acd = FALSE;
1471#endif
1472
1473 (void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
1474 (void)win_comp_pos(); // recompute window positions
1475 p_ea = save_ea;
1476#ifdef FEAT_AUTOCHDIR
1477 p_acd = save_acd;
1478#endif
1479 unblock_autocmds();
1480 curwin = aucmd_win;
1481 }
1482 curbuf = buf;
1483 aco->new_curwin = curwin;
1484 set_bufref(&aco->new_curbuf, curbuf);
1485}
1486
1487/*
1488 * Cleanup after executing autocommands for a (hidden) buffer.
1489 * Restore the window as it was (if possible).
1490 */
1491 void
1492aucmd_restbuf(
1493 aco_save_T *aco) // structure holding saved values
1494{
1495 int dummy;
1496
1497 if (aco->use_aucmd_win)
1498 {
1499 --curbuf->b_nwindows;
1500 // Find "aucmd_win", it can't be closed, but it may be in another tab
1501 // page. Do not trigger autocommands here.
1502 block_autocmds();
1503 if (curwin != aucmd_win)
1504 {
1505 tabpage_T *tp;
1506 win_T *wp;
1507
1508 FOR_ALL_TAB_WINDOWS(tp, wp)
1509 {
1510 if (wp == aucmd_win)
1511 {
1512 if (tp != curtab)
1513 goto_tabpage_tp(tp, TRUE, TRUE);
1514 win_goto(aucmd_win);
1515 goto win_found;
1516 }
1517 }
1518 }
1519win_found:
1520
1521 // Remove the window and frame from the tree of frames.
1522 (void)winframe_remove(curwin, &dummy, NULL);
1523 win_remove(curwin, NULL);
1524 aucmd_win_used = FALSE;
1525 last_status(FALSE); // may need to remove last status line
1526
1527 if (!valid_tabpage_win(curtab))
1528 // no valid window in current tabpage
1529 close_tabpage(curtab);
1530
1531 restore_snapshot(SNAP_AUCMD_IDX, FALSE);
1532 (void)win_comp_pos(); // recompute window positions
1533 unblock_autocmds();
1534
1535 if (win_valid(aco->save_curwin))
Bram Moolenaarbdf931c2020-10-01 22:37:40 +02001536 curwin = aco->save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001537 else
1538 // Hmm, original window disappeared. Just use the first one.
1539 curwin = firstwin;
Bram Moolenaarbdf931c2020-10-01 22:37:40 +02001540 curbuf = curwin->w_buffer;
1541#ifdef FEAT_JOB_CHANNEL
1542 // May need to restore insert mode for a prompt buffer.
1543 entering_window(curwin);
1544#endif
1545
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001546 if (win_valid(aco->save_prevwin))
1547 prevwin = aco->save_prevwin;
1548#ifdef FEAT_EVAL
1549 vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables
1550 hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab
1551#endif
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001552 vim_free(globaldir);
1553 globaldir = aco->globaldir;
1554
1555 // the buffer contents may have changed
1556 check_cursor();
1557 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1558 {
1559 curwin->w_topline = curbuf->b_ml.ml_line_count;
1560#ifdef FEAT_DIFF
1561 curwin->w_topfill = 0;
1562#endif
1563 }
1564#if defined(FEAT_GUI)
1565 // Hide the scrollbars from the aucmd_win and update.
1566 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_LEFT], FALSE);
1567 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
1568 gui_may_update_scrollbars();
1569#endif
1570 }
1571 else
1572 {
1573 // restore curwin
1574 if (win_valid(aco->save_curwin))
1575 {
1576 // Restore the buffer which was previously edited by curwin, if
1577 // it was changed, we are still the same window and the buffer is
1578 // valid.
1579 if (curwin == aco->new_curwin
1580 && curbuf != aco->new_curbuf.br_buf
1581 && bufref_valid(&aco->new_curbuf)
1582 && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL)
1583 {
1584# if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
1585 if (curwin->w_s == &curbuf->b_s)
1586 curwin->w_s = &aco->new_curbuf.br_buf->b_s;
1587# endif
1588 --curbuf->b_nwindows;
1589 curbuf = aco->new_curbuf.br_buf;
1590 curwin->w_buffer = curbuf;
1591 ++curbuf->b_nwindows;
1592 }
1593
1594 curwin = aco->save_curwin;
1595 curbuf = curwin->w_buffer;
1596 if (win_valid(aco->save_prevwin))
1597 prevwin = aco->save_prevwin;
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001598 // In case the autocommand moves the cursor to a position that
1599 // does not exist in curbuf.
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001600 check_cursor();
1601 }
1602 }
1603}
1604
1605static int autocmd_nested = FALSE;
1606
1607/*
1608 * Execute autocommands for "event" and file name "fname".
1609 * Return TRUE if some commands were executed.
1610 */
1611 int
1612apply_autocmds(
1613 event_T event,
1614 char_u *fname, // NULL or empty means use actual file name
1615 char_u *fname_io, // fname to use for <afile> on cmdline
1616 int force, // when TRUE, ignore autocmd_busy
1617 buf_T *buf) // buffer for <abuf>
1618{
1619 return apply_autocmds_group(event, fname, fname_io, force,
1620 AUGROUP_ALL, buf, NULL);
1621}
1622
1623/*
1624 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
1625 * setting v:filearg.
1626 */
1627 int
1628apply_autocmds_exarg(
1629 event_T event,
1630 char_u *fname,
1631 char_u *fname_io,
1632 int force,
1633 buf_T *buf,
1634 exarg_T *eap)
1635{
1636 return apply_autocmds_group(event, fname, fname_io, force,
1637 AUGROUP_ALL, buf, eap);
1638}
1639
1640/*
1641 * Like apply_autocmds(), but handles the caller's retval. If the script
1642 * processing is being aborted or if retval is FAIL when inside a try
1643 * conditional, no autocommands are executed. If otherwise the autocommands
1644 * cause the script to be aborted, retval is set to FAIL.
1645 */
1646 int
1647apply_autocmds_retval(
1648 event_T event,
1649 char_u *fname, // NULL or empty means use actual file name
1650 char_u *fname_io, // fname to use for <afile> on cmdline
1651 int force, // when TRUE, ignore autocmd_busy
1652 buf_T *buf, // buffer for <abuf>
1653 int *retval) // pointer to caller's retval
1654{
1655 int did_cmd;
1656
1657#ifdef FEAT_EVAL
1658 if (should_abort(*retval))
1659 return FALSE;
1660#endif
1661
1662 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
1663 AUGROUP_ALL, buf, NULL);
1664 if (did_cmd
1665#ifdef FEAT_EVAL
1666 && aborting()
1667#endif
1668 )
1669 *retval = FAIL;
1670 return did_cmd;
1671}
1672
1673/*
1674 * Return TRUE when there is a CursorHold autocommand defined.
1675 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02001676 static int
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001677has_cursorhold(void)
1678{
1679 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
1680 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
1681}
1682
1683/*
1684 * Return TRUE if the CursorHold event can be triggered.
1685 */
1686 int
1687trigger_cursorhold(void)
1688{
1689 int state;
1690
1691 if (!did_cursorhold
1692 && has_cursorhold()
1693 && reg_recording == 0
1694 && typebuf.tb_len == 0
Bram Moolenaare2c453d2019-08-21 14:37:09 +02001695 && !ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001696 {
1697 state = get_real_state();
1698 if (state == NORMAL_BUSY || (state & INSERT) != 0)
1699 return TRUE;
1700 }
1701 return FALSE;
1702}
1703
1704/*
1705 * Return TRUE when there is a CursorMoved autocommand defined.
1706 */
1707 int
1708has_cursormoved(void)
1709{
1710 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
1711}
1712
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001713/*
1714 * Return TRUE when there is a CursorMovedI autocommand defined.
1715 */
1716 int
1717has_cursormovedI(void)
1718{
1719 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
1720}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001721
1722/*
1723 * Return TRUE when there is a TextChanged autocommand defined.
1724 */
1725 int
1726has_textchanged(void)
1727{
1728 return (first_autopat[(int)EVENT_TEXTCHANGED] != NULL);
1729}
1730
1731/*
1732 * Return TRUE when there is a TextChangedI autocommand defined.
1733 */
1734 int
1735has_textchangedI(void)
1736{
1737 return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL);
1738}
1739
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001740/*
1741 * Return TRUE when there is a TextChangedP autocommand defined.
1742 */
1743 int
1744has_textchangedP(void)
1745{
1746 return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL);
1747}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001748
1749/*
1750 * Return TRUE when there is an InsertCharPre autocommand defined.
1751 */
1752 int
1753has_insertcharpre(void)
1754{
1755 return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL);
1756}
1757
1758/*
1759 * Return TRUE when there is an CmdUndefined autocommand defined.
1760 */
1761 int
1762has_cmdundefined(void)
1763{
1764 return (first_autopat[(int)EVENT_CMDUNDEFINED] != NULL);
1765}
1766
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001767#if defined(FEAT_EVAL) || defined(PROTO)
1768/*
1769 * Return TRUE when there is a TextYankPost autocommand defined.
1770 */
1771 int
1772has_textyankpost(void)
1773{
1774 return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL);
1775}
1776#endif
1777
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001778#if defined(FEAT_EVAL) || defined(PROTO)
1779/*
1780 * Return TRUE when there is a CompleteChanged autocommand defined.
1781 */
1782 int
1783has_completechanged(void)
1784{
1785 return (first_autopat[(int)EVENT_COMPLETECHANGED] != NULL);
1786}
1787#endif
1788
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001789/*
1790 * Execute autocommands for "event" and file name "fname".
1791 * Return TRUE if some commands were executed.
1792 */
1793 static int
1794apply_autocmds_group(
1795 event_T event,
1796 char_u *fname, // NULL or empty means use actual file name
1797 char_u *fname_io, // fname to use for <afile> on cmdline, NULL means
1798 // use fname
1799 int force, // when TRUE, ignore autocmd_busy
1800 int group, // group ID, or AUGROUP_ALL
1801 buf_T *buf, // buffer for <abuf>
1802 exarg_T *eap UNUSED) // command arguments
1803{
1804 char_u *sfname = NULL; // short file name
1805 char_u *tail;
1806 int save_changed;
1807 buf_T *old_curbuf;
1808 int retval = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001809 char_u *save_autocmd_fname;
1810 int save_autocmd_fname_full;
1811 int save_autocmd_bufnr;
1812 char_u *save_autocmd_match;
1813 int save_autocmd_busy;
1814 int save_autocmd_nested;
1815 static int nesting = 0;
1816 AutoPatCmd patcmd;
1817 AutoPat *ap;
1818#ifdef FEAT_EVAL
1819 sctx_T save_current_sctx;
1820 funccal_entry_T funccal_entry;
1821 char_u *save_cmdarg;
1822 long save_cmdbang;
1823#endif
1824 static int filechangeshell_busy = FALSE;
1825#ifdef FEAT_PROFILE
1826 proftime_T wait_time;
1827#endif
1828 int did_save_redobuff = FALSE;
1829 save_redo_T save_redo;
1830 int save_KeyTyped = KeyTyped;
Bram Moolenaare31ee862020-01-07 20:59:34 +01001831 ESTACK_CHECK_DECLARATION
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001832
1833 /*
1834 * Quickly return if there are no autocommands for this event or
1835 * autocommands are blocked.
1836 */
1837 if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
1838 || autocmd_blocked > 0)
1839 goto BYPASS_AU;
1840
1841 /*
1842 * When autocommands are busy, new autocommands are only executed when
1843 * explicitly enabled with the "nested" flag.
1844 */
1845 if (autocmd_busy && !(force || autocmd_nested))
1846 goto BYPASS_AU;
1847
1848#ifdef FEAT_EVAL
1849 /*
1850 * Quickly return when immediately aborting on error, or when an interrupt
1851 * occurred or an exception was thrown but not caught.
1852 */
1853 if (aborting())
1854 goto BYPASS_AU;
1855#endif
1856
1857 /*
1858 * FileChangedShell never nests, because it can create an endless loop.
1859 */
1860 if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
1861 || event == EVENT_FILECHANGEDSHELLPOST))
1862 goto BYPASS_AU;
1863
1864 /*
1865 * Ignore events in 'eventignore'.
1866 */
1867 if (event_ignored(event))
1868 goto BYPASS_AU;
1869
1870 /*
1871 * Allow nesting of autocommands, but restrict the depth, because it's
1872 * possible to create an endless loop.
1873 */
1874 if (nesting == 10)
1875 {
1876 emsg(_("E218: autocommand nesting too deep"));
1877 goto BYPASS_AU;
1878 }
1879
1880 /*
1881 * Check if these autocommands are disabled. Used when doing ":all" or
1882 * ":ball".
1883 */
1884 if ( (autocmd_no_enter
1885 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
1886 || (autocmd_no_leave
1887 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
1888 goto BYPASS_AU;
1889
1890 /*
1891 * Save the autocmd_* variables and info about the current buffer.
1892 */
1893 save_autocmd_fname = autocmd_fname;
1894 save_autocmd_fname_full = autocmd_fname_full;
1895 save_autocmd_bufnr = autocmd_bufnr;
1896 save_autocmd_match = autocmd_match;
1897 save_autocmd_busy = autocmd_busy;
1898 save_autocmd_nested = autocmd_nested;
1899 save_changed = curbuf->b_changed;
1900 old_curbuf = curbuf;
1901
1902 /*
1903 * Set the file name to be used for <afile>.
1904 * Make a copy to avoid that changing a buffer name or directory makes it
1905 * invalid.
1906 */
1907 if (fname_io == NULL)
1908 {
1909 if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
1910 || event == EVENT_OPTIONSET)
1911 autocmd_fname = NULL;
1912 else if (fname != NULL && !ends_excmd(*fname))
1913 autocmd_fname = fname;
1914 else if (buf != NULL)
1915 autocmd_fname = buf->b_ffname;
1916 else
1917 autocmd_fname = NULL;
1918 }
1919 else
1920 autocmd_fname = fname_io;
1921 if (autocmd_fname != NULL)
1922 autocmd_fname = vim_strsave(autocmd_fname);
1923 autocmd_fname_full = FALSE; // call FullName_save() later
1924
1925 /*
1926 * Set the buffer number to be used for <abuf>.
1927 */
1928 if (buf == NULL)
1929 autocmd_bufnr = 0;
1930 else
1931 autocmd_bufnr = buf->b_fnum;
1932
1933 /*
1934 * When the file name is NULL or empty, use the file name of buffer "buf".
1935 * Always use the full path of the file name to match with, in case
1936 * "allow_dirs" is set.
1937 */
1938 if (fname == NULL || *fname == NUL)
1939 {
1940 if (buf == NULL)
1941 fname = NULL;
1942 else
1943 {
1944#ifdef FEAT_SYN_HL
1945 if (event == EVENT_SYNTAX)
1946 fname = buf->b_p_syn;
1947 else
1948#endif
1949 if (event == EVENT_FILETYPE)
1950 fname = buf->b_p_ft;
1951 else
1952 {
1953 if (buf->b_sfname != NULL)
1954 sfname = vim_strsave(buf->b_sfname);
1955 fname = buf->b_ffname;
1956 }
1957 }
1958 if (fname == NULL)
1959 fname = (char_u *)"";
1960 fname = vim_strsave(fname); // make a copy, so we can change it
1961 }
1962 else
1963 {
1964 sfname = vim_strsave(fname);
1965 // Don't try expanding FileType, Syntax, FuncUndefined, WindowID,
1966 // ColorScheme, QuickFixCmd* or DirChanged
1967 if (event == EVENT_FILETYPE
1968 || event == EVENT_SYNTAX
1969 || event == EVENT_CMDLINECHANGED
1970 || event == EVENT_CMDLINEENTER
1971 || event == EVENT_CMDLINELEAVE
1972 || event == EVENT_CMDWINENTER
1973 || event == EVENT_CMDWINLEAVE
1974 || event == EVENT_CMDUNDEFINED
1975 || event == EVENT_FUNCUNDEFINED
1976 || event == EVENT_REMOTEREPLY
1977 || event == EVENT_SPELLFILEMISSING
1978 || event == EVENT_QUICKFIXCMDPRE
1979 || event == EVENT_COLORSCHEME
1980 || event == EVENT_COLORSCHEMEPRE
1981 || event == EVENT_OPTIONSET
1982 || event == EVENT_QUICKFIXCMDPOST
1983 || event == EVENT_DIRCHANGED)
1984 {
1985 fname = vim_strsave(fname);
1986 autocmd_fname_full = TRUE; // don't expand it later
1987 }
1988 else
1989 fname = FullName_save(fname, FALSE);
1990 }
1991 if (fname == NULL) // out of memory
1992 {
1993 vim_free(sfname);
1994 retval = FALSE;
1995 goto BYPASS_AU;
1996 }
1997
1998#ifdef BACKSLASH_IN_FILENAME
1999 /*
2000 * Replace all backslashes with forward slashes. This makes the
2001 * autocommand patterns portable between Unix and MS-DOS.
2002 */
2003 if (sfname != NULL)
2004 forward_slash(sfname);
2005 forward_slash(fname);
2006#endif
2007
2008#ifdef VMS
2009 // remove version for correct match
2010 if (sfname != NULL)
2011 vms_remove_version(sfname);
2012 vms_remove_version(fname);
2013#endif
2014
2015 /*
2016 * Set the name to be used for <amatch>.
2017 */
2018 autocmd_match = fname;
2019
2020
2021 // Don't redraw while doing autocommands.
2022 ++RedrawingDisabled;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002023
2024 // name and lnum are filled in later
2025 estack_push(ETYPE_AUCMD, NULL, 0);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002026 ESTACK_CHECK_SETUP
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002027
2028#ifdef FEAT_EVAL
2029 save_current_sctx = current_sctx;
2030
2031# ifdef FEAT_PROFILE
2032 if (do_profiling == PROF_YES)
2033 prof_child_enter(&wait_time); // doesn't count for the caller itself
2034# endif
2035
2036 // Don't use local function variables, if called from a function.
2037 save_funccal(&funccal_entry);
2038#endif
2039
2040 /*
2041 * When starting to execute autocommands, save the search patterns.
2042 */
2043 if (!autocmd_busy)
2044 {
2045 save_search_patterns();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002046 if (!ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002047 {
2048 saveRedobuff(&save_redo);
2049 did_save_redobuff = TRUE;
2050 }
2051 did_filetype = keep_filetype;
2052 }
2053
2054 /*
2055 * Note that we are applying autocmds. Some commands need to know.
2056 */
2057 autocmd_busy = TRUE;
2058 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
2059 ++nesting; // see matching decrement below
2060
2061 // Remember that FileType was triggered. Used for did_filetype().
2062 if (event == EVENT_FILETYPE)
2063 did_filetype = TRUE;
2064
2065 tail = gettail(fname);
2066
2067 // Find first autocommand that matches
2068 patcmd.curpat = first_autopat[(int)event];
2069 patcmd.nextcmd = NULL;
2070 patcmd.group = group;
2071 patcmd.fname = fname;
2072 patcmd.sfname = sfname;
2073 patcmd.tail = tail;
2074 patcmd.event = event;
2075 patcmd.arg_bufnr = autocmd_bufnr;
2076 patcmd.next = NULL;
2077 auto_next_pat(&patcmd, FALSE);
2078
2079 // found one, start executing the autocommands
2080 if (patcmd.curpat != NULL)
2081 {
2082 // add to active_apc_list
2083 patcmd.next = active_apc_list;
2084 active_apc_list = &patcmd;
2085
2086#ifdef FEAT_EVAL
2087 // set v:cmdarg (only when there is a matching pattern)
2088 save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
2089 if (eap != NULL)
2090 {
2091 save_cmdarg = set_cmdarg(eap, NULL);
2092 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
2093 }
2094 else
2095 save_cmdarg = NULL; // avoid gcc warning
2096#endif
2097 retval = TRUE;
2098 // mark the last pattern, to avoid an endless loop when more patterns
2099 // are added when executing autocommands
2100 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
2101 ap->last = FALSE;
2102 ap->last = TRUE;
Bram Moolenaara68e5952019-04-25 22:22:01 +02002103
2104 // make sure cursor and topline are valid
2105 check_lnums(TRUE);
2106
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002107 do_cmdline(NULL, getnextac, (void *)&patcmd,
2108 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
Bram Moolenaara68e5952019-04-25 22:22:01 +02002109
2110 // restore cursor and topline, unless they were changed
2111 reset_lnums();
2112
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002113#ifdef FEAT_EVAL
2114 if (eap != NULL)
2115 {
2116 (void)set_cmdarg(NULL, save_cmdarg);
2117 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
2118 }
2119#endif
2120 // delete from active_apc_list
2121 if (active_apc_list == &patcmd) // just in case
2122 active_apc_list = patcmd.next;
2123 }
2124
2125 --RedrawingDisabled;
2126 autocmd_busy = save_autocmd_busy;
2127 filechangeshell_busy = FALSE;
2128 autocmd_nested = save_autocmd_nested;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002129 vim_free(SOURCING_NAME);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002130 ESTACK_CHECK_NOW
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002131 estack_pop();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002132 vim_free(autocmd_fname);
2133 autocmd_fname = save_autocmd_fname;
2134 autocmd_fname_full = save_autocmd_fname_full;
2135 autocmd_bufnr = save_autocmd_bufnr;
2136 autocmd_match = save_autocmd_match;
2137#ifdef FEAT_EVAL
2138 current_sctx = save_current_sctx;
2139 restore_funccal();
2140# ifdef FEAT_PROFILE
2141 if (do_profiling == PROF_YES)
2142 prof_child_exit(&wait_time);
2143# endif
2144#endif
2145 KeyTyped = save_KeyTyped;
2146 vim_free(fname);
2147 vim_free(sfname);
2148 --nesting; // see matching increment above
2149
2150 /*
2151 * When stopping to execute autocommands, restore the search patterns and
2152 * the redo buffer. Free any buffers in the au_pending_free_buf list and
2153 * free any windows in the au_pending_free_win list.
2154 */
2155 if (!autocmd_busy)
2156 {
2157 restore_search_patterns();
2158 if (did_save_redobuff)
2159 restoreRedobuff(&save_redo);
2160 did_filetype = FALSE;
2161 while (au_pending_free_buf != NULL)
2162 {
2163 buf_T *b = au_pending_free_buf->b_next;
2164 vim_free(au_pending_free_buf);
2165 au_pending_free_buf = b;
2166 }
2167 while (au_pending_free_win != NULL)
2168 {
2169 win_T *w = au_pending_free_win->w_next;
2170 vim_free(au_pending_free_win);
2171 au_pending_free_win = w;
2172 }
2173 }
2174
2175 /*
2176 * Some events don't set or reset the Changed flag.
2177 * Check if still in the same buffer!
2178 */
2179 if (curbuf == old_curbuf
2180 && (event == EVENT_BUFREADPOST
2181 || event == EVENT_BUFWRITEPOST
2182 || event == EVENT_FILEAPPENDPOST
2183 || event == EVENT_VIMLEAVE
2184 || event == EVENT_VIMLEAVEPRE))
2185 {
2186#ifdef FEAT_TITLE
2187 if (curbuf->b_changed != save_changed)
2188 need_maketitle = TRUE;
2189#endif
2190 curbuf->b_changed = save_changed;
2191 }
2192
2193 au_cleanup(); // may really delete removed patterns/commands now
2194
2195BYPASS_AU:
2196 // When wiping out a buffer make sure all its buffer-local autocommands
2197 // are deleted.
2198 if (event == EVENT_BUFWIPEOUT && buf != NULL)
2199 aubuflocal_remove(buf);
2200
2201 if (retval == OK && event == EVENT_FILETYPE)
2202 au_did_filetype = TRUE;
2203
2204 return retval;
2205}
2206
2207# ifdef FEAT_EVAL
2208static char_u *old_termresponse = NULL;
2209# endif
2210
2211/*
2212 * Block triggering autocommands until unblock_autocmd() is called.
2213 * Can be used recursively, so long as it's symmetric.
2214 */
2215 void
2216block_autocmds(void)
2217{
2218# ifdef FEAT_EVAL
2219 // Remember the value of v:termresponse.
2220 if (autocmd_blocked == 0)
2221 old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
2222# endif
2223 ++autocmd_blocked;
2224}
2225
2226 void
2227unblock_autocmds(void)
2228{
2229 --autocmd_blocked;
2230
2231# ifdef FEAT_EVAL
2232 // When v:termresponse was set while autocommands were blocked, trigger
2233 // the autocommands now. Esp. useful when executing a shell command
2234 // during startup (vimdiff).
2235 if (autocmd_blocked == 0
2236 && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
2237 apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
2238# endif
2239}
2240
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002241 int
2242is_autocmd_blocked(void)
2243{
2244 return autocmd_blocked != 0;
2245}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002246
2247/*
2248 * Find next autocommand pattern that matches.
2249 */
2250 static void
2251auto_next_pat(
2252 AutoPatCmd *apc,
2253 int stop_at_last) // stop when 'last' flag is set
2254{
2255 AutoPat *ap;
2256 AutoCmd *cp;
2257 char_u *name;
2258 char *s;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002259 char_u **sourcing_namep = &SOURCING_NAME;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002260
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002261 VIM_CLEAR(*sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002262
2263 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
2264 {
2265 apc->curpat = NULL;
2266
2267 // Only use a pattern when it has not been removed, has commands and
2268 // the group matches. For buffer-local autocommands only check the
2269 // buffer number.
2270 if (ap->pat != NULL && ap->cmds != NULL
2271 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
2272 {
2273 // execution-condition
2274 if (ap->buflocal_nr == 0
2275 ? (match_file_pat(NULL, &ap->reg_prog, apc->fname,
2276 apc->sfname, apc->tail, ap->allow_dirs))
2277 : ap->buflocal_nr == apc->arg_bufnr)
2278 {
2279 name = event_nr2name(apc->event);
2280 s = _("%s Autocommands for \"%s\"");
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002281 *sourcing_namep = alloc(STRLEN(s)
Bram Moolenaar964b3742019-05-24 18:54:09 +02002282 + STRLEN(name) + ap->patlen + 1);
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002283 if (*sourcing_namep != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002284 {
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002285 sprintf((char *)*sourcing_namep, s,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002286 (char *)name, (char *)ap->pat);
2287 if (p_verbose >= 8)
2288 {
2289 verbose_enter();
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002290 smsg(_("Executing %s"), *sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002291 verbose_leave();
2292 }
2293 }
2294
2295 apc->curpat = ap;
2296 apc->nextcmd = ap->cmds;
2297 // mark last command
2298 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
2299 cp->last = FALSE;
2300 cp->last = TRUE;
2301 }
2302 line_breakcheck();
2303 if (apc->curpat != NULL) // found a match
2304 break;
2305 }
2306 if (stop_at_last && ap->last)
2307 break;
2308 }
2309}
2310
2311/*
2312 * Get next autocommand command.
2313 * Called by do_cmdline() to get the next line for ":if".
2314 * Returns allocated string, or NULL for end of autocommands.
2315 */
2316 char_u *
Bram Moolenaar66250c92020-08-20 15:02:42 +02002317getnextac(
2318 int c UNUSED,
2319 void *cookie,
2320 int indent UNUSED,
2321 getline_opt_T options UNUSED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002322{
2323 AutoPatCmd *acp = (AutoPatCmd *)cookie;
2324 char_u *retval;
2325 AutoCmd *ac;
2326
2327 // Can be called again after returning the last line.
2328 if (acp->curpat == NULL)
2329 return NULL;
2330
2331 // repeat until we find an autocommand to execute
2332 for (;;)
2333 {
2334 // skip removed commands
2335 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
2336 if (acp->nextcmd->last)
2337 acp->nextcmd = NULL;
2338 else
2339 acp->nextcmd = acp->nextcmd->next;
2340
2341 if (acp->nextcmd != NULL)
2342 break;
2343
2344 // at end of commands, find next pattern that matches
2345 if (acp->curpat->last)
2346 acp->curpat = NULL;
2347 else
2348 acp->curpat = acp->curpat->next;
2349 if (acp->curpat != NULL)
2350 auto_next_pat(acp, TRUE);
2351 if (acp->curpat == NULL)
2352 return NULL;
2353 }
2354
2355 ac = acp->nextcmd;
2356
2357 if (p_verbose >= 9)
2358 {
2359 verbose_enter_scroll();
2360 smsg(_("autocommand %s"), ac->cmd);
2361 msg_puts("\n"); // don't overwrite this either
2362 verbose_leave_scroll();
2363 }
2364 retval = vim_strsave(ac->cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02002365 // Remove one-shot ("once") autocmd in anticipation of its execution.
2366 if (ac->once)
2367 au_del_cmd(ac);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002368 autocmd_nested = ac->nested;
2369#ifdef FEAT_EVAL
2370 current_sctx = ac->script_ctx;
2371#endif
2372 if (ac->last)
2373 acp->nextcmd = NULL;
2374 else
2375 acp->nextcmd = ac->next;
2376 return retval;
2377}
2378
2379/*
2380 * Return TRUE if there is a matching autocommand for "fname".
2381 * To account for buffer-local autocommands, function needs to know
2382 * in which buffer the file will be opened.
2383 */
2384 int
2385has_autocmd(event_T event, char_u *sfname, buf_T *buf)
2386{
2387 AutoPat *ap;
2388 char_u *fname;
2389 char_u *tail = gettail(sfname);
2390 int retval = FALSE;
2391
2392 fname = FullName_save(sfname, FALSE);
2393 if (fname == NULL)
2394 return FALSE;
2395
2396#ifdef BACKSLASH_IN_FILENAME
2397 /*
2398 * Replace all backslashes with forward slashes. This makes the
2399 * autocommand patterns portable between Unix and MS-DOS.
2400 */
2401 sfname = vim_strsave(sfname);
2402 if (sfname != NULL)
2403 forward_slash(sfname);
2404 forward_slash(fname);
2405#endif
2406
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002407 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002408 if (ap->pat != NULL && ap->cmds != NULL
2409 && (ap->buflocal_nr == 0
2410 ? match_file_pat(NULL, &ap->reg_prog,
2411 fname, sfname, tail, ap->allow_dirs)
2412 : buf != NULL && ap->buflocal_nr == buf->b_fnum
2413 ))
2414 {
2415 retval = TRUE;
2416 break;
2417 }
2418
2419 vim_free(fname);
2420#ifdef BACKSLASH_IN_FILENAME
2421 vim_free(sfname);
2422#endif
2423
2424 return retval;
2425}
2426
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002427/*
2428 * Function given to ExpandGeneric() to obtain the list of autocommand group
2429 * names.
2430 */
2431 char_u *
2432get_augroup_name(expand_T *xp UNUSED, int idx)
2433{
2434 if (idx == augroups.ga_len) // add "END" add the end
2435 return (char_u *)"END";
2436 if (idx >= augroups.ga_len) // end of list
2437 return NULL;
2438 if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup())
2439 // skip deleted entries
2440 return (char_u *)"";
2441 return AUGROUP_NAME(idx); // return a name
2442}
2443
2444static int include_groups = FALSE;
2445
2446 char_u *
2447set_context_in_autocmd(
2448 expand_T *xp,
2449 char_u *arg,
2450 int doautocmd) // TRUE for :doauto*, FALSE for :autocmd
2451{
2452 char_u *p;
2453 int group;
2454
2455 // check for a group name, skip it if present
2456 include_groups = FALSE;
2457 p = arg;
2458 group = au_get_grouparg(&arg);
2459 if (group == AUGROUP_ERROR)
2460 return NULL;
2461 // If there only is a group name that's what we expand.
2462 if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1]))
2463 {
2464 arg = p;
2465 group = AUGROUP_ALL;
2466 }
2467
2468 // skip over event name
2469 for (p = arg; *p != NUL && !VIM_ISWHITE(*p); ++p)
2470 if (*p == ',')
2471 arg = p + 1;
2472 if (*p == NUL)
2473 {
2474 if (group == AUGROUP_ALL)
2475 include_groups = TRUE;
2476 xp->xp_context = EXPAND_EVENTS; // expand event name
2477 xp->xp_pattern = arg;
2478 return NULL;
2479 }
2480
2481 // skip over pattern
2482 arg = skipwhite(p);
2483 while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\'))
2484 arg++;
2485 if (*arg)
2486 return arg; // expand (next) command
2487
2488 if (doautocmd)
2489 xp->xp_context = EXPAND_FILES; // expand file names
2490 else
2491 xp->xp_context = EXPAND_NOTHING; // pattern is not expanded
2492 return NULL;
2493}
2494
2495/*
2496 * Function given to ExpandGeneric() to obtain the list of event names.
2497 */
2498 char_u *
2499get_event_name(expand_T *xp UNUSED, int idx)
2500{
2501 if (idx < augroups.ga_len) // First list group names, if wanted
2502 {
2503 if (!include_groups || AUGROUP_NAME(idx) == NULL
2504 || AUGROUP_NAME(idx) == get_deleted_augroup())
2505 return (char_u *)""; // skip deleted entries
2506 return AUGROUP_NAME(idx); // return a name
2507 }
2508 return (char_u *)event_names[idx - augroups.ga_len].name;
2509}
2510
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002511
2512#if defined(FEAT_EVAL) || defined(PROTO)
2513/*
2514 * Return TRUE if autocmd is supported.
2515 */
2516 int
2517autocmd_supported(char_u *name)
2518{
2519 char_u *p;
2520
2521 return (event_name2nr(name, &p) != NUM_EVENTS);
2522}
2523
2524/*
2525 * Return TRUE if an autocommand is defined for a group, event and
2526 * pattern: The group can be omitted to accept any group. "event" and "pattern"
2527 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
2528 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
2529 * Used for:
2530 * exists("#Group") or
2531 * exists("#Group#Event") or
2532 * exists("#Group#Event#pat") or
2533 * exists("#Event") or
2534 * exists("#Event#pat")
2535 */
2536 int
2537au_exists(char_u *arg)
2538{
2539 char_u *arg_save;
2540 char_u *pattern = NULL;
2541 char_u *event_name;
2542 char_u *p;
2543 event_T event;
2544 AutoPat *ap;
2545 buf_T *buflocal_buf = NULL;
2546 int group;
2547 int retval = FALSE;
2548
2549 // Make a copy so that we can change the '#' chars to a NUL.
2550 arg_save = vim_strsave(arg);
2551 if (arg_save == NULL)
2552 return FALSE;
2553 p = vim_strchr(arg_save, '#');
2554 if (p != NULL)
2555 *p++ = NUL;
2556
2557 // First, look for an autocmd group name
2558 group = au_find_group(arg_save);
2559 if (group == AUGROUP_ERROR)
2560 {
2561 // Didn't match a group name, assume the first argument is an event.
2562 group = AUGROUP_ALL;
2563 event_name = arg_save;
2564 }
2565 else
2566 {
2567 if (p == NULL)
2568 {
2569 // "Group": group name is present and it's recognized
2570 retval = TRUE;
2571 goto theend;
2572 }
2573
2574 // Must be "Group#Event" or "Group#Event#pat".
2575 event_name = p;
2576 p = vim_strchr(event_name, '#');
2577 if (p != NULL)
2578 *p++ = NUL; // "Group#Event#pat"
2579 }
2580
2581 pattern = p; // "pattern" is NULL when there is no pattern
2582
2583 // find the index (enum) for the event name
2584 event = event_name2nr(event_name, &p);
2585
2586 // return FALSE if the event name is not recognized
2587 if (event == NUM_EVENTS)
2588 goto theend;
2589
2590 // Find the first autocommand for this event.
2591 // If there isn't any, return FALSE;
2592 // If there is one and no pattern given, return TRUE;
2593 ap = first_autopat[(int)event];
2594 if (ap == NULL)
2595 goto theend;
2596
2597 // if pattern is "<buffer>", special handling is needed which uses curbuf
2598 // for pattern "<buffer=N>, fnamecmp() will work fine
2599 if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0)
2600 buflocal_buf = curbuf;
2601
2602 // Check if there is an autocommand with the given pattern.
2603 for ( ; ap != NULL; ap = ap->next)
2604 // only use a pattern when it has not been removed and has commands.
2605 // For buffer-local autocommands, fnamecmp() works fine.
2606 if (ap->pat != NULL && ap->cmds != NULL
2607 && (group == AUGROUP_ALL || ap->group == group)
2608 && (pattern == NULL
2609 || (buflocal_buf == NULL
2610 ? fnamecmp(ap->pat, pattern) == 0
2611 : ap->buflocal_nr == buflocal_buf->b_fnum)))
2612 {
2613 retval = TRUE;
2614 break;
2615 }
2616
2617theend:
2618 vim_free(arg_save);
2619 return retval;
2620}
2621#endif