1 // This is an open source non-commercial project. Dear PVS-Studio, please check
2 // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
3 
4 // autocmd.c: Autocommand related functions
5 
6 #include "nvim/api/private/helpers.h"
7 #include "nvim/ascii.h"
8 #include "nvim/autocmd.h"
9 #include "nvim/buffer.h"
10 #include "nvim/charset.h"
11 #include "nvim/cursor.h"
12 #include "nvim/edit.h"
13 #include "nvim/eval.h"
14 #include "nvim/eval/userfunc.h"
15 #include "nvim/ex_docmd.h"
16 #include "nvim/fileio.h"
17 #include "nvim/getchar.h"
18 #include "nvim/misc1.h"
19 #include "nvim/option.h"
20 #include "nvim/regexp.h"
21 #include "nvim/search.h"
22 #include "nvim/state.h"
23 #include "nvim/ui_compositor.h"
24 #include "nvim/vim.h"
25 
26 #ifdef INCLUDE_GENERATED_DECLARATIONS
27 # include "auevents_name_map.generated.h"
28 # include "autocmd.c.generated.h"
29 #endif
30 
31 //
32 // The autocommands are stored in a list for each event.
33 // Autocommands for the same pattern, that are consecutive, are joined
34 // together, to avoid having to match the pattern too often.
35 // The result is an array of Autopat lists, which point to AutoCmd lists:
36 //
37 // last_autopat[0]  -----------------------------+
38 //                                               V
39 // first_autopat[0] --> Autopat.next  -->  Autopat.next -->  NULL
40 //                      Autopat.cmds       Autopat.cmds
41 //                          |                    |
42 //                          V                    V
43 //                      AutoCmd.next       AutoCmd.next
44 //                          |                    |
45 //                          V                    V
46 //                      AutoCmd.next            NULL
47 //                          |
48 //                          V
49 //                         NULL
50 //
51 // last_autopat[1]  --------+
52 //                          V
53 // first_autopat[1] --> Autopat.next  -->  NULL
54 //                      Autopat.cmds
55 //                          |
56 //                          V
57 //                      AutoCmd.next
58 //                          |
59 //                          V
60 //                         NULL
61 //   etc.
62 //
63 //   The order of AutoCmds is important, this is the order in which they were
64 //   defined and will have to be executed.
65 //
66 
67 // Code for automatic commands.
68 static AutoPatCmd *active_apc_list = NULL;  // stack of active autocommands
69 
70 /// List of autocmd group names
71 static garray_T augroups = { 0, 0, sizeof(char_u *), 10, NULL };
72 #define AUGROUP_NAME(i) (((char **)augroups.ga_data)[i])
73 #define BUFLOCAL_PAT_LEN 25
74 
75 // use get_deleted_augroup() to get this
76 static const char *deleted_augroup = NULL;
77 
78 // The ID of the current group.  Group 0 is the default one.
79 static int current_augroup = AUGROUP_DEFAULT;
80 
81 static int au_need_clean = false;  // need to delete marked patterns
82 
83 static event_T last_event;
84 static int last_group;
85 static int autocmd_blocked = 0;  // block all autocmds
86 
87 static bool autocmd_nested = false;
88 static bool autocmd_include_groups = false;
89 
90 static char_u *old_termresponse = NULL;
91 
get_deleted_augroup(void)92 static inline const char *get_deleted_augroup(void) FUNC_ATTR_ALWAYS_INLINE
93 {
94   if (deleted_augroup == NULL) {
95     deleted_augroup = _("--Deleted--");
96   }
97   return deleted_augroup;
98 }
99 
100 // Show the autocommands for one AutoPat.
show_autocmd(AutoPat * ap,event_T event)101 static void show_autocmd(AutoPat *ap, event_T event)
102 {
103   AutoCmd *ac;
104 
105   // Check for "got_int" (here and at various places below), which is set
106   // when "q" has been hit for the "--more--" prompt
107   if (got_int) {
108     return;
109   }
110   // pattern has been removed
111   if (ap->pat == NULL) {
112     return;
113   }
114 
115   msg_putchar('\n');
116   if (got_int) {
117     return;
118   }
119   if (event != last_event || ap->group != last_group) {
120     if (ap->group != AUGROUP_DEFAULT) {
121       if (AUGROUP_NAME(ap->group) == NULL) {
122         msg_puts_attr(get_deleted_augroup(), HL_ATTR(HLF_E));
123       } else {
124         msg_puts_attr(AUGROUP_NAME(ap->group), HL_ATTR(HLF_T));
125       }
126       msg_puts("  ");
127     }
128     msg_puts_attr(event_nr2name(event), HL_ATTR(HLF_T));
129     last_event = event;
130     last_group = ap->group;
131     msg_putchar('\n');
132     if (got_int) {
133       return;
134     }
135   }
136   msg_col = 4;
137   msg_outtrans(ap->pat);
138 
139   for (ac = ap->cmds; ac != NULL; ac = ac->next) {
140     if (ac->cmd == NULL) {  // skip removed commands
141       continue;
142     }
143     if (msg_col >= 14) {
144       msg_putchar('\n');
145     }
146     msg_col = 14;
147     if (got_int) {
148       return;
149     }
150     msg_outtrans(ac->cmd);
151     if (p_verbose > 0) {
152       last_set_msg(ac->script_ctx);
153     }
154     if (got_int) {
155       return;
156     }
157     if (ac->next != NULL) {
158       msg_putchar('\n');
159       if (got_int) {
160         return;
161       }
162     }
163   }
164 }
165 
166 // Mark an autocommand handler for deletion.
au_remove_pat(AutoPat * ap)167 static void au_remove_pat(AutoPat *ap)
168 {
169   XFREE_CLEAR(ap->pat);
170   ap->buflocal_nr = -1;
171   au_need_clean = true;
172 }
173 
174 // Mark all commands for a pattern for deletion.
au_remove_cmds(AutoPat * ap)175 static void au_remove_cmds(AutoPat *ap)
176 {
177   for (AutoCmd *ac = ap->cmds; ac != NULL; ac = ac->next) {
178     XFREE_CLEAR(ac->cmd);
179   }
180   au_need_clean = true;
181 }
182 
183 // Delete one command from an autocmd pattern.
au_del_cmd(AutoCmd * ac)184 static void au_del_cmd(AutoCmd *ac)
185 {
186   XFREE_CLEAR(ac->cmd);
187   au_need_clean = true;
188 }
189 
190 /// Cleanup autocommands and patterns that have been deleted.
191 /// This is only done when not executing autocommands.
au_cleanup(void)192 static void au_cleanup(void)
193 {
194   AutoPat *ap, **prev_ap;
195   event_T event;
196 
197   if (autocmd_busy || !au_need_clean) {
198     return;
199   }
200 
201   // Loop over all events.
202   for (event = (event_T)0; (int)event < NUM_EVENTS;
203        event = (event_T)((int)event + 1)) {
204     // Loop over all autocommand patterns.
205     prev_ap = &(first_autopat[(int)event]);
206     for (ap = *prev_ap; ap != NULL; ap = *prev_ap) {
207       bool has_cmd = false;
208 
209       // Loop over all commands for this pattern.
210       AutoCmd **prev_ac = &(ap->cmds);
211       for (AutoCmd *ac = *prev_ac; ac != NULL; ac = *prev_ac) {
212         // Remove the command if the pattern is to be deleted or when
213         // the command has been marked for deletion.
214         if (ap->pat == NULL || ac->cmd == NULL) {
215           *prev_ac = ac->next;
216           xfree(ac->cmd);
217           xfree(ac);
218         } else {
219           has_cmd = true;
220           prev_ac = &(ac->next);
221         }
222       }
223 
224       if (ap->pat != NULL && !has_cmd) {
225         // Pattern was not marked for deletion, but all of its commands were.
226         // So mark the pattern for deletion.
227         au_remove_pat(ap);
228       }
229 
230       // Remove the pattern if it has been marked for deletion.
231       if (ap->pat == NULL) {
232         if (ap->next == NULL) {
233           if (prev_ap == &(first_autopat[(int)event])) {
234             last_autopat[(int)event] = NULL;
235           } else {
236             // this depends on the "next" field being the first in
237             // the struct
238             last_autopat[(int)event] = (AutoPat *)prev_ap;
239           }
240         }
241         *prev_ap = ap->next;
242         vim_regfree(ap->reg_prog);
243         xfree(ap);
244       } else {
245         prev_ap = &(ap->next);
246       }
247     }
248   }
249 
250   au_need_clean = false;
251 }
252 
253 // Called when buffer is freed, to remove/invalidate related buffer-local
254 // autocmds.
aubuflocal_remove(buf_T * buf)255 void aubuflocal_remove(buf_T *buf)
256 {
257   AutoPat *ap;
258   event_T event;
259   AutoPatCmd *apc;
260 
261   // invalidate currently executing autocommands
262   for (apc = active_apc_list; apc; apc = apc->next) {
263     if (buf->b_fnum == apc->arg_bufnr) {
264       apc->arg_bufnr = 0;
265     }
266   }
267 
268   // invalidate buflocals looping through events
269   for (event = (event_T)0; (int)event < NUM_EVENTS;
270        event = (event_T)((int)event + 1)) {
271     // loop over all autocommand patterns
272     for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) {
273       if (ap->buflocal_nr == buf->b_fnum) {
274         au_remove_pat(ap);
275         if (p_verbose >= 6) {
276           verbose_enter();
277           smsg(_("auto-removing autocommand: %s <buffer=%d>"),
278                event_nr2name(event), buf->b_fnum);
279           verbose_leave();
280         }
281       }
282     }
283   }
284   au_cleanup();
285 }
286 
287 // Add an autocmd group name.
288 // Return its ID.  Returns AUGROUP_ERROR (< 0) for error.
au_new_group(char_u * name)289 static int au_new_group(char_u *name)
290 {
291   int i = au_find_group(name);
292   if (i == AUGROUP_ERROR) {  // the group doesn't exist yet, add it.
293     // First try using a free entry.
294     for (i = 0; i < augroups.ga_len; i++) {
295       if (AUGROUP_NAME(i) == NULL) {
296         break;
297       }
298     }
299     if (i == augroups.ga_len) {
300       ga_grow(&augroups, 1);
301     }
302 
303     AUGROUP_NAME(i) = xstrdup((char *)name);
304     if (i == augroups.ga_len) {
305       augroups.ga_len++;
306     }
307   }
308 
309   return i;
310 }
311 
au_del_group(char_u * name)312 static void au_del_group(char_u *name)
313 {
314   int i = au_find_group(name);
315   if (i == AUGROUP_ERROR) {  // the group doesn't exist
316     semsg(_("E367: No such group: \"%s\""), name);
317   } else if (i == current_augroup) {
318     emsg(_("E936: Cannot delete the current group"));
319   } else {
320     event_T event;
321     AutoPat *ap;
322     int in_use = false;
323 
324     for (event = (event_T)0; (int)event < NUM_EVENTS;
325          event = (event_T)((int)event + 1)) {
326       for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) {
327         if (ap->group == i && ap->pat != NULL) {
328           give_warning((char_u *)_("W19: Deleting augroup that is still in use"), true);
329           in_use = true;
330           event = NUM_EVENTS;
331           break;
332         }
333       }
334     }
335     xfree(AUGROUP_NAME(i));
336     if (in_use) {
337       AUGROUP_NAME(i) = (char *)get_deleted_augroup();
338     } else {
339       AUGROUP_NAME(i) = NULL;
340     }
341   }
342 }
343 
344 /// Find the ID of an autocmd group name.
345 ///
346 /// @param name augroup name
347 ///
348 /// @return the ID or AUGROUP_ERROR (< 0) for error.
au_find_group(const char_u * name)349 static int au_find_group(const char_u *name)
350   FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
351 {
352   for (int i = 0; i < augroups.ga_len; i++) {
353     if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup()
354         && STRCMP(AUGROUP_NAME(i), name) == 0) {
355       return i;
356     }
357   }
358   return AUGROUP_ERROR;
359 }
360 
361 /// Return true if augroup "name" exists.
362 ///
363 /// @param name augroup name
au_has_group(const char_u * name)364 bool au_has_group(const char_u *name)
365   FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
366 {
367   return au_find_group(name) != AUGROUP_ERROR;
368 }
369 
370 /// ":augroup {name}".
do_augroup(char_u * arg,int del_group)371 void do_augroup(char_u *arg, int del_group)
372 {
373   if (del_group) {
374     if (*arg == NUL) {
375       emsg(_(e_argreq));
376     } else {
377       au_del_group(arg);
378     }
379   } else if (STRICMP(arg, "end") == 0) {  // ":aug end": back to group 0
380     current_augroup = AUGROUP_DEFAULT;
381   } else if (*arg) {  // ":aug xxx": switch to group xxx
382     int i = au_new_group(arg);
383     if (i != AUGROUP_ERROR) {
384       current_augroup = i;
385     }
386   } else {  // ":aug": list the group names
387     msg_start();
388     for (int i = 0; i < augroups.ga_len; i++) {
389       if (AUGROUP_NAME(i) != NULL) {
390         msg_puts(AUGROUP_NAME(i));
391         msg_puts("  ");
392       }
393     }
394     msg_clr_eos();
395     msg_end();
396   }
397 }
398 
399 #if defined(EXITFREE)
free_all_autocmds(void)400 void free_all_autocmds(void)
401 {
402   for (current_augroup = -1; current_augroup < augroups.ga_len;
403        current_augroup++) {
404     do_autocmd((char_u *)"", true);
405   }
406 
407   for (int i = 0; i < augroups.ga_len; i++) {
408     char *const s = ((char **)(augroups.ga_data))[i];
409     if ((const char *)s != get_deleted_augroup()) {
410       xfree(s);
411     }
412   }
413   ga_clear(&augroups);
414 }
415 #endif
416 
417 // Return the event number for event name "start".
418 // Return NUM_EVENTS if the event name was not found.
419 // Return a pointer to the next event name in "end".
event_name2nr(const char_u * start,char_u ** end)420 static event_T event_name2nr(const char_u *start, char_u **end)
421 {
422   const char_u *p;
423   int i;
424   int len;
425 
426   // the event name ends with end of line, '|', a blank or a comma
427   for (p = start; *p && !ascii_iswhite(*p) && *p != ',' && *p != '|'; p++) {
428   }
429   for (i = 0; event_names[i].name != NULL; i++) {
430     len = (int)event_names[i].len;
431     if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0) {
432       break;
433     }
434   }
435   if (*p == ',') {
436     p++;
437   }
438   *end = (char_u *)p;
439   if (event_names[i].name == NULL) {
440     return NUM_EVENTS;
441   }
442   return event_names[i].event;
443 }
444 
445 /// Return the name for event
446 ///
447 /// @param[in]  event  Event to return name for.
448 ///
449 /// @return Event name, static string. Returns "Unknown" for unknown events.
event_nr2name(event_T event)450 static const char *event_nr2name(event_T event)
451   FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_CONST
452 {
453   int i;
454 
455   for (i = 0; event_names[i].name != NULL; i++) {
456     if (event_names[i].event == event) {
457       return event_names[i].name;
458     }
459   }
460   return "Unknown";
461 }
462 
463 /// Scan over the events.  "*" stands for all events.
464 /// true when group name was found
find_end_event(char_u * arg,int have_group)465 static char_u *find_end_event(char_u *arg, int have_group)
466 {
467   char_u *pat;
468   char_u *p;
469 
470   if (*arg == '*') {
471     if (arg[1] && !ascii_iswhite(arg[1])) {
472       semsg(_("E215: Illegal character after *: %s"), arg);
473       return NULL;
474     }
475     pat = arg + 1;
476   } else {
477     for (pat = arg; *pat && *pat != '|' && !ascii_iswhite(*pat); pat = p) {
478       if ((int)event_name2nr(pat, &p) >= NUM_EVENTS) {
479         if (have_group) {
480           semsg(_("E216: No such event: %s"), pat);
481         } else {
482           semsg(_("E216: No such group or event: %s"), pat);
483         }
484         return NULL;
485       }
486     }
487   }
488   return pat;
489 }
490 
491 /// Return true if "event" is included in 'eventignore'.
492 ///
493 /// @param event event to check
event_ignored(event_T event)494 static bool event_ignored(event_T event)
495   FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
496 {
497   char_u *p = p_ei;
498 
499   while (*p != NUL) {
500     if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ',')) {
501       return true;
502     }
503     if (event_name2nr(p, &p) == event) {
504       return true;
505     }
506   }
507 
508   return false;
509 }
510 
511 // Return OK when the contents of p_ei is valid, FAIL otherwise.
check_ei(void)512 int check_ei(void)
513 {
514   char_u *p = p_ei;
515 
516   while (*p) {
517     if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ',')) {
518       p += 3;
519       if (*p == ',') {
520         p++;
521       }
522     } else if (event_name2nr(p, &p) == NUM_EVENTS) {
523       return FAIL;
524     }
525   }
526 
527   return OK;
528 }
529 
530 // Add "what" to 'eventignore' to skip loading syntax highlighting for every
531 // buffer loaded into the window.  "what" must start with a comma.
532 // Returns the old value of 'eventignore' in allocated memory.
au_event_disable(char * what)533 char_u *au_event_disable(char *what)
534 {
535   char_u *new_ei;
536   char_u *save_ei;
537 
538   save_ei = vim_strsave(p_ei);
539   new_ei = vim_strnsave(p_ei, STRLEN(p_ei) + STRLEN(what));
540   if (*what == ',' && *p_ei == NUL) {
541     STRCPY(new_ei, what + 1);
542   } else {
543     STRCAT(new_ei, what);
544   }
545   set_string_option_direct("ei", -1, new_ei, OPT_FREE, SID_NONE);
546   xfree(new_ei);
547 
548   return save_ei;
549 }
550 
au_event_restore(char_u * old_ei)551 void au_event_restore(char_u *old_ei)
552 {
553   if (old_ei != NULL) {
554     set_string_option_direct("ei", -1, old_ei, OPT_FREE, SID_NONE);
555     xfree(old_ei);
556   }
557 }
558 
559 // Implements :autocmd.
560 // Defines an autocmd (does not execute; cf. apply_autocmds_group).
561 //
562 // Can be used in the following ways:
563 //
564 // :autocmd <event> <pat> <cmd>     Add <cmd> to the list of commands that
565 //                                  will be automatically executed for <event>
566 //                                  when editing a file matching <pat>, in
567 //                                  the current group.
568 // :autocmd <event> <pat>           Show the autocommands associated with
569 //                                  <event> and <pat>.
570 // :autocmd <event>                 Show the autocommands associated with
571 //                                  <event>.
572 // :autocmd                         Show all autocommands.
573 // :autocmd! <event> <pat> <cmd>    Remove all autocommands associated with
574 //                                  <event> and <pat>, and add the command
575 //                                  <cmd>, for the current group.
576 // :autocmd! <event> <pat>          Remove all autocommands associated with
577 //                                  <event> and <pat> for the current group.
578 // :autocmd! <event>                Remove all autocommands associated with
579 //                                  <event> for the current group.
580 // :autocmd!                        Remove ALL autocommands for the current
581 //                                  group.
582 //
583 //  Multiple events and patterns may be given separated by commas.  Here are
584 //  some examples:
585 // :autocmd bufread,bufenter *.c,*.h    set tw=0 smartindent noic
586 // :autocmd bufleave         *          set tw=79 nosmartindent ic infercase
587 //
588 // :autocmd * *.c               show all autocommands for *.c files.
589 //
590 // Mostly a {group} argument can optionally appear before <event>.
do_autocmd(char_u * arg_in,int forceit)591 void do_autocmd(char_u *arg_in, int forceit)
592 {
593   char_u *arg = arg_in;
594   char_u *pat;
595   char_u *envpat = NULL;
596   char_u *cmd;
597   int need_free = false;
598   int nested = false;
599   bool once = false;
600   int group;
601 
602   if (*arg == '|') {
603     arg = (char_u *)"";
604     group = AUGROUP_ALL;  // no argument, use all groups
605   } else {
606     // Check for a legal group name.  If not, use AUGROUP_ALL.
607     group = au_get_grouparg(&arg);
608   }
609 
610   // Scan over the events.
611   // If we find an illegal name, return here, don't do anything.
612   pat = find_end_event(arg, group != AUGROUP_ALL);
613   if (pat == NULL) {
614     return;
615   }
616 
617   pat = skipwhite(pat);
618   if (*pat == '|') {
619     pat = (char_u *)"";
620     cmd = (char_u *)"";
621   } else {
622     // Scan over the pattern.  Put a NUL at the end.
623     cmd = pat;
624     while (*cmd && (!ascii_iswhite(*cmd) || cmd[-1] == '\\')) {
625       cmd++;
626     }
627     if (*cmd) {
628       *cmd++ = NUL;
629     }
630 
631     // Expand environment variables in the pattern.  Set 'shellslash', we want
632     // forward slashes here.
633     if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL) {
634 #ifdef BACKSLASH_IN_FILENAME
635       int p_ssl_save = p_ssl;
636 
637       p_ssl = true;
638 #endif
639       envpat = expand_env_save(pat);
640 #ifdef BACKSLASH_IN_FILENAME
641       p_ssl = p_ssl_save;
642 #endif
643       if (envpat != NULL) {
644         pat = envpat;
645       }
646     }
647 
648     cmd = skipwhite(cmd);
649     for (size_t i = 0; i < 2; i++) {
650       if (*cmd != NUL) {
651         // Check for "++once" flag.
652         if (STRNCMP(cmd, "++once", 6) == 0 && ascii_iswhite(cmd[6])) {
653           if (once) {
654             semsg(_(e_duparg2), "++once");
655           }
656           once = true;
657           cmd = skipwhite(cmd + 6);
658         }
659 
660         // Check for "++nested" flag.
661         if ((STRNCMP(cmd, "++nested", 8) == 0 && ascii_iswhite(cmd[8]))) {
662           if (nested) {
663             semsg(_(e_duparg2), "++nested");
664           }
665           nested = true;
666           cmd = skipwhite(cmd + 8);
667         }
668 
669         // Check for the old (deprecated) "nested" flag.
670         if (STRNCMP(cmd, "nested", 6) == 0 && ascii_iswhite(cmd[6])) {
671           if (nested) {
672             semsg(_(e_duparg2), "nested");
673           }
674           nested = true;
675           cmd = skipwhite(cmd + 6);
676         }
677       }
678     }
679 
680     // Find the start of the commands.
681     // Expand <sfile> in it.
682     if (*cmd != NUL) {
683       cmd = expand_sfile(cmd);
684       if (cmd == NULL) {  // some error
685         return;
686       }
687       need_free = true;
688     }
689   }
690 
691   // Print header when showing autocommands.
692   if (!forceit && *cmd == NUL) {
693     // Highlight title
694     msg_puts_title(_("\n--- Autocommands ---"));
695   }
696 
697   // Loop over the events.
698   last_event = (event_T)-1;    // for listing the event name
699   last_group = AUGROUP_ERROR;  // for listing the group name
700   if (*arg == '*' || *arg == NUL || *arg == '|') {
701     if (!forceit && *cmd != NUL) {
702       emsg(_(e_cannot_define_autocommands_for_all_events));
703     } else {
704       for (event_T event = (event_T)0; event < NUM_EVENTS;
705            event = (event_T)(event + 1)) {
706         if (do_autocmd_event(event, pat, once, nested, cmd, forceit, group)
707             == FAIL) {
708           break;
709         }
710       }
711     }
712   } else {
713     while (*arg && *arg != '|' && !ascii_iswhite(*arg)) {
714       event_T event = event_name2nr(arg, &arg);
715       assert(event < NUM_EVENTS);
716       if (do_autocmd_event(event, pat, once, nested, cmd, forceit, group)
717           == FAIL) {
718         break;
719       }
720     }
721   }
722 
723   if (need_free) {
724     xfree(cmd);
725   }
726   xfree(envpat);
727 }
728 
729 // Find the group ID in a ":autocmd" or ":doautocmd" argument.
730 // The "argp" argument is advanced to the following argument.
731 //
732 // Returns the group ID or AUGROUP_ALL.
au_get_grouparg(char_u ** argp)733 static int au_get_grouparg(char_u **argp)
734 {
735   char_u *group_name;
736   char_u *p;
737   char_u *arg = *argp;
738   int group = AUGROUP_ALL;
739 
740   for (p = arg; *p && !ascii_iswhite(*p) && *p != '|'; p++) {
741   }
742   if (p > arg) {
743     group_name = vim_strnsave(arg, (size_t)(p - arg));
744     group = au_find_group(group_name);
745     if (group == AUGROUP_ERROR) {
746       group = AUGROUP_ALL;  // no match, use all groups
747     } else {
748       *argp = skipwhite(p);  // match, skip over group name
749     }
750     xfree(group_name);
751   }
752   return group;
753 }
754 
755 // do_autocmd() for one event.
756 // Defines an autocmd (does not execute; cf. apply_autocmds_group).
757 //
758 // If *pat == NUL: do for all patterns.
759 // If *cmd == NUL: show entries.
760 // If forceit == true: delete entries.
761 // If group is not AUGROUP_ALL: only use this group.
do_autocmd_event(event_T event,char_u * pat,bool once,int nested,char_u * cmd,int forceit,int group)762 static int do_autocmd_event(event_T event, char_u *pat, bool once, int nested, char_u *cmd,
763                             int forceit, int group)
764 {
765   AutoPat *ap;
766   AutoPat **prev_ap;
767   AutoCmd *ac;
768   AutoCmd **prev_ac;
769   int brace_level;
770   char_u *endpat;
771   int findgroup;
772   int allgroups;
773   int patlen;
774   int is_buflocal;
775   int buflocal_nr;
776   char_u buflocal_pat[BUFLOCAL_PAT_LEN];  // for "<buffer=X>"
777 
778   if (group == AUGROUP_ALL) {
779     findgroup = current_augroup;
780   } else {
781     findgroup = group;
782   }
783   allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
784 
785   // Show or delete all patterns for an event.
786   if (*pat == NUL) {
787     for (ap = first_autopat[event]; ap != NULL; ap = ap->next) {
788       if (forceit) {  // delete the AutoPat, if it's in the current group
789         if (ap->group == findgroup) {
790           au_remove_pat(ap);
791         }
792       } else if (group == AUGROUP_ALL || ap->group == group) {
793         show_autocmd(ap, event);
794       }
795     }
796   }
797 
798   // Loop through all the specified patterns.
799   for (; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat)) {
800     // Find end of the pattern.
801     // Watch out for a comma in braces, like "*.\{obj,o\}".
802     endpat = pat;
803     // ignore single comma
804     if (*endpat == ',') {
805       continue;
806     }
807     brace_level = 0;
808     for (; *endpat && (*endpat != ',' || brace_level || endpat[-1] == '\\');
809          endpat++) {
810       if (*endpat == '{') {
811         brace_level++;
812       } else if (*endpat == '}') {
813         brace_level--;
814       }
815     }
816     patlen = (int)(endpat - pat);
817 
818     // detect special <buflocal[=X]> buffer-local patterns
819     is_buflocal = false;
820     buflocal_nr = 0;
821 
822     if (patlen >= 8 && STRNCMP(pat, "<buffer", 7) == 0
823         && pat[patlen - 1] == '>') {
824       // "<buffer...>": Error will be printed only for addition.
825       // printing and removing will proceed silently.
826       is_buflocal = true;
827       if (patlen == 8) {
828         // "<buffer>"
829         buflocal_nr = curbuf->b_fnum;
830       } else if (patlen > 9 && pat[7] == '=') {
831         if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13) == 0) {
832           // "<buffer=abuf>"
833           buflocal_nr = autocmd_bufnr;
834         } else if (skipdigits(pat + 8) == pat + patlen - 1) {
835           // "<buffer=123>"
836           buflocal_nr = atoi((char *)pat + 8);
837         }
838       }
839     }
840 
841     if (is_buflocal) {
842       // normalize pat into standard "<buffer>#N" form
843       snprintf((char *)buflocal_pat,
844                BUFLOCAL_PAT_LEN,
845                "<buffer=%d>",
846                buflocal_nr);
847 
848       pat = buflocal_pat;                  // can modify pat and patlen
849       patlen = (int)STRLEN(buflocal_pat);  //   but not endpat
850     }
851 
852     // Find AutoPat entries with this pattern.  When adding a command it
853     // always goes at or after the last one, so start at the end.
854     if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL) {
855       prev_ap = &last_autopat[(int)event];
856     } else {
857       prev_ap = &first_autopat[(int)event];
858     }
859     while ((ap = *prev_ap) != NULL) {
860       if (ap->pat != NULL) {
861         // Accept a pattern when:
862         // - a group was specified and it's that group, or a group was
863         //   not specified and it's the current group, or a group was
864         //   not specified and we are listing
865         // - the length of the pattern matches
866         // - the pattern matches.
867         // For <buffer[=X]>, this condition works because we normalize
868         // all buffer-local patterns.
869         if ((allgroups || ap->group == findgroup) && ap->patlen == patlen
870             && STRNCMP(pat, ap->pat, patlen) == 0) {
871           // Remove existing autocommands.
872           // If adding any new autocmd's for this AutoPat, don't
873           // delete the pattern from the autopat list, append to
874           // this list.
875           if (forceit) {
876             if (*cmd != NUL && ap->next == NULL) {
877               au_remove_cmds(ap);
878               break;
879             }
880             au_remove_pat(ap);
881           } else if (*cmd == NUL) {
882             // Show autocmd's for this autopat, or buflocals <buffer=X>
883             show_autocmd(ap, event);
884           } else if (ap->next == NULL) {
885             // Add autocmd to this autopat, if it's the last one.
886             break;
887           }
888         }
889       }
890       prev_ap = &ap->next;
891     }
892 
893     // Add a new command.
894     if (*cmd != NUL) {
895       // If the pattern we want to add a command to does appear at the
896       // end of the list (or not is not in the list at all), add the
897       // pattern at the end of the list.
898       if (ap == NULL) {
899         // refuse to add buffer-local ap if buffer number is invalid
900         if (is_buflocal
901             && (buflocal_nr == 0 || buflist_findnr(buflocal_nr) == NULL)) {
902           semsg(_("E680: <buffer=%d>: invalid buffer number "), buflocal_nr);
903           return FAIL;
904         }
905 
906         ap = xmalloc(sizeof(AutoPat));
907         ap->pat = vim_strnsave(pat, (size_t)patlen);
908         ap->patlen = patlen;
909 
910         if (is_buflocal) {
911           ap->buflocal_nr = buflocal_nr;
912           ap->reg_prog = NULL;
913         } else {
914           char_u *reg_pat;
915 
916           ap->buflocal_nr = 0;
917           reg_pat = file_pat_to_reg_pat(pat, endpat, &ap->allow_dirs, true);
918           if (reg_pat != NULL) {
919             ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
920           }
921           xfree(reg_pat);
922           if (reg_pat == NULL || ap->reg_prog == NULL) {
923             xfree(ap->pat);
924             xfree(ap);
925             return FAIL;
926           }
927         }
928         ap->cmds = NULL;
929         *prev_ap = ap;
930         last_autopat[(int)event] = ap;
931         ap->next = NULL;
932         if (group == AUGROUP_ALL) {
933           ap->group = current_augroup;
934         } else {
935           ap->group = group;
936         }
937       }
938 
939       // Add the autocmd at the end of the AutoCmd list.
940       prev_ac = &(ap->cmds);
941       while ((ac = *prev_ac) != NULL) {
942         prev_ac = &ac->next;
943       }
944       ac = xmalloc(sizeof(AutoCmd));
945       ac->cmd = vim_strsave(cmd);
946       ac->script_ctx = current_sctx;
947       ac->script_ctx.sc_lnum += sourcing_lnum;
948       ac->next = NULL;
949       *prev_ac = ac;
950       ac->once = once;
951       ac->nested = nested;
952     }
953   }
954 
955   au_cleanup();  // may really delete removed patterns/commands now
956   return OK;
957 }
958 
959 /// Implementation of ":doautocmd [group] event [fname]".
960 /// Return OK for success, FAIL for failure;
961 ///
962 /// @param do_msg  give message for no matching autocmds?
do_doautocmd(char_u * arg,bool do_msg,bool * did_something)963 int do_doautocmd(char_u *arg, bool do_msg, bool *did_something)
964 {
965   char_u *fname;
966   int nothing_done = true;
967   int group;
968 
969   if (did_something != NULL) {
970     *did_something = false;
971   }
972 
973   // Check for a legal group name.  If not, use AUGROUP_ALL.
974   group = au_get_grouparg(&arg);
975 
976   if (*arg == '*') {
977     emsg(_("E217: Can't execute autocommands for ALL events"));
978     return FAIL;
979   }
980 
981   // Scan over the events.
982   // If we find an illegal name, return here, don't do anything.
983   fname = find_end_event(arg, group != AUGROUP_ALL);
984   if (fname == NULL) {
985     return FAIL;
986   }
987 
988   fname = skipwhite(fname);
989 
990   // Loop over the events.
991   while (*arg && !ends_excmd(*arg) && !ascii_iswhite(*arg)) {
992     if (apply_autocmds_group(event_name2nr(arg, &arg), fname, NULL, true, group,
993                              curbuf, NULL)) {
994       nothing_done = false;
995     }
996   }
997 
998   if (nothing_done && do_msg) {
999     msg(_("No matching autocommands"));
1000   }
1001   if (did_something != NULL) {
1002     *did_something = !nothing_done;
1003   }
1004 
1005   return aborting() ? FAIL : OK;
1006 }
1007 
1008 // ":doautoall": execute autocommands for each loaded buffer.
ex_doautoall(exarg_T * eap)1009 void ex_doautoall(exarg_T *eap)
1010 {
1011   int retval = OK;
1012   aco_save_T aco;
1013   char_u *arg = eap->arg;
1014   int call_do_modelines = check_nomodeline(&arg);
1015   bufref_T bufref;
1016   bool did_aucmd;
1017 
1018   // This is a bit tricky: For some commands curwin->w_buffer needs to be
1019   // equal to curbuf, but for some buffers there may not be a window.
1020   // So we change the buffer for the current window for a moment.  This
1021   // gives problems when the autocommands make changes to the list of
1022   // buffers or windows...
1023   FOR_ALL_BUFFERS(buf) {
1024     // Only do loaded buffers and skip the current buffer, it's done last.
1025     if (buf->b_ml.ml_mfp == NULL || buf == curbuf) {
1026       continue;
1027     }
1028     // Find a window for this buffer and save some values.
1029     aucmd_prepbuf(&aco, buf);
1030     set_bufref(&bufref, buf);
1031 
1032     // execute the autocommands for this buffer
1033     retval = do_doautocmd(arg, false, &did_aucmd);
1034 
1035     if (call_do_modelines && did_aucmd) {
1036       // Execute the modeline settings, but don't set window-local
1037       // options if we are using the current window for another
1038       // buffer.
1039       do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
1040     }
1041 
1042     // restore the current window
1043     aucmd_restbuf(&aco);
1044 
1045     // Stop if there is some error or buffer was deleted.
1046     if (retval == FAIL || !bufref_valid(&bufref)) {
1047       retval = FAIL;
1048       break;
1049     }
1050   }
1051 
1052   // Execute autocommands for the current buffer last.
1053   if (retval == OK) {
1054     (void)do_doautocmd(arg, false, &did_aucmd);
1055     if (call_do_modelines && did_aucmd) {
1056       do_modelines(0);
1057     }
1058   }
1059 
1060   check_cursor();  // just in case lines got deleted
1061 }
1062 
1063 /// Check *argp for <nomodeline>.  When it is present return false, otherwise
1064 /// return true and advance *argp to after it. Thus do_modelines() should be
1065 /// called when true is returned.
1066 ///
1067 /// @param[in,out] argp argument string
check_nomodeline(char_u ** argp)1068 bool check_nomodeline(char_u **argp)
1069   FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
1070 {
1071   if (STRNCMP(*argp, "<nomodeline>", 12) == 0) {
1072     *argp = skipwhite(*argp + 12);
1073     return false;
1074   }
1075   return true;
1076 }
1077 
1078 /// Prepare for executing autocommands for (hidden) buffer `buf`.
1079 /// If the current buffer is not in any visible window, put it in a temporary
1080 /// floating window `aucmd_win`.
1081 /// Set `curbuf` and `curwin` to match `buf`.
1082 ///
1083 /// @param aco  structure to save values in
1084 /// @param buf  new curbuf
aucmd_prepbuf(aco_save_T * aco,buf_T * buf)1085 void aucmd_prepbuf(aco_save_T *aco, buf_T *buf)
1086 {
1087   win_T *win;
1088   bool need_append = true;  // Append `aucmd_win` to the window list.
1089 
1090   // Find a window that is for the new buffer
1091   if (buf == curbuf) {  // be quick when buf is curbuf
1092     win = curwin;
1093   } else {
1094     win = NULL;
1095     FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
1096       if (wp->w_buffer == buf) {
1097         win = wp;
1098         break;
1099       }
1100     }
1101   }
1102 
1103   // Allocate the `aucmd_win` dummy floating window.
1104   if (win == NULL && aucmd_win == NULL) {
1105     win_alloc_aucmd_win();
1106     need_append = false;
1107   }
1108   if (win == NULL && aucmd_win_used) {
1109     // Strange recursive autocommand, fall back to using the current
1110     // window.  Expect a few side effects...
1111     win = curwin;
1112   }
1113 
1114   aco->save_curwin_handle = curwin->handle;
1115   aco->save_curbuf = curbuf;
1116   aco->save_prevwin_handle = prevwin == NULL ? 0 : prevwin->handle;
1117   if (win != NULL) {
1118     // There is a window for "buf" in the current tab page, make it the
1119     // curwin.  This is preferred, it has the least side effects (esp. if
1120     // "buf" is curbuf).
1121     aco->use_aucmd_win = false;
1122     curwin = win;
1123   } else {
1124     // There is no window for "buf", use "aucmd_win".  To minimize the side
1125     // effects, insert it in the current tab page.
1126     // Anything related to a window (e.g., setting folds) may have
1127     // unexpected results.
1128     aco->use_aucmd_win = true;
1129     aucmd_win_used = true;
1130     aucmd_win->w_buffer = buf;
1131     aucmd_win->w_s = &buf->b_s;
1132     buf->b_nwindows++;
1133     win_init_empty(aucmd_win);  // set cursor and topline to safe values
1134 
1135     // Make sure w_localdir and globaldir are NULL to avoid a chdir() in
1136     // win_enter_ext().
1137     XFREE_CLEAR(aucmd_win->w_localdir);
1138     aco->globaldir = globaldir;
1139     globaldir = NULL;
1140 
1141     block_autocmds();  // We don't want BufEnter/WinEnter autocommands.
1142     if (need_append) {
1143       win_append(lastwin, aucmd_win);
1144       pmap_put(handle_T)(&window_handles, aucmd_win->handle, aucmd_win);
1145       win_config_float(aucmd_win, aucmd_win->w_float_config);
1146     }
1147     // Prevent chdir() call in win_enter_ext(), through do_autochdir()
1148     int save_acd = p_acd;
1149     p_acd = false;
1150     win_enter(aucmd_win, false);
1151     p_acd = save_acd;
1152     unblock_autocmds();
1153     curwin = aucmd_win;
1154   }
1155   curbuf = buf;
1156   aco->new_curwin_handle = curwin->handle;
1157   set_bufref(&aco->new_curbuf, curbuf);
1158 }
1159 
1160 /// Cleanup after executing autocommands for a (hidden) buffer.
1161 /// Restore the window as it was (if possible).
1162 ///
1163 /// @param aco  structure holding saved values
aucmd_restbuf(aco_save_T * aco)1164 void aucmd_restbuf(aco_save_T *aco)
1165 {
1166   if (aco->use_aucmd_win) {
1167     curbuf->b_nwindows--;
1168     // Find "aucmd_win", it can't be closed, but it may be in another tab page.
1169     // Do not trigger autocommands here.
1170     block_autocmds();
1171     if (curwin != aucmd_win) {
1172       FOR_ALL_TAB_WINDOWS(tp, wp) {
1173         if (wp == aucmd_win) {
1174           if (tp != curtab) {
1175             goto_tabpage_tp(tp, true, true);
1176           }
1177           win_goto(aucmd_win);
1178           goto win_found;
1179         }
1180       }
1181     }
1182 win_found:
1183 
1184     win_remove(curwin, NULL);
1185     pmap_del(handle_T)(&window_handles, curwin->handle);
1186     if (curwin->w_grid_alloc.chars != NULL) {
1187       ui_comp_remove_grid(&curwin->w_grid_alloc);
1188       ui_call_win_hide(curwin->w_grid_alloc.handle);
1189       grid_free(&curwin->w_grid_alloc);
1190     }
1191 
1192     aucmd_win_used = false;
1193     last_status(false);  // may need to remove last status line
1194 
1195     if (!valid_tabpage_win(curtab)) {
1196       // no valid window in current tabpage
1197       close_tabpage(curtab);
1198     }
1199 
1200     unblock_autocmds();
1201 
1202     win_T *const save_curwin = win_find_by_handle(aco->save_curwin_handle);
1203     if (save_curwin != NULL) {
1204       curwin = save_curwin;
1205     } else {
1206       // Hmm, original window disappeared.  Just use the first one.
1207       curwin = firstwin;
1208     }
1209     prevwin = win_find_by_handle(aco->save_prevwin_handle);
1210     vars_clear(&aucmd_win->w_vars->dv_hashtab);         // free all w: variables
1211     hash_init(&aucmd_win->w_vars->dv_hashtab);          // re-use the hashtab
1212     curbuf = curwin->w_buffer;
1213 
1214     xfree(globaldir);
1215     globaldir = aco->globaldir;
1216 
1217     // the buffer contents may have changed
1218     check_cursor();
1219     if (curwin->w_topline > curbuf->b_ml.ml_line_count) {
1220       curwin->w_topline = curbuf->b_ml.ml_line_count;
1221       curwin->w_topfill = 0;
1222     }
1223   } else {
1224     // Restore curwin.  Use the window ID, a window may have been closed
1225     // and the memory re-used for another one.
1226     win_T *const save_curwin = win_find_by_handle(aco->save_curwin_handle);
1227     if (save_curwin != NULL) {
1228       // Restore the buffer which was previously edited by curwin, if it was
1229       // changed, we are still the same window and the buffer is valid.
1230       if (curwin->handle == aco->new_curwin_handle
1231           && curbuf != aco->new_curbuf.br_buf
1232           && bufref_valid(&aco->new_curbuf)
1233           && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL) {
1234         if (curwin->w_s == &curbuf->b_s) {
1235           curwin->w_s = &aco->new_curbuf.br_buf->b_s;
1236         }
1237         curbuf->b_nwindows--;
1238         curbuf = aco->new_curbuf.br_buf;
1239         curwin->w_buffer = curbuf;
1240         curbuf->b_nwindows++;
1241       }
1242 
1243       curwin = save_curwin;
1244       curbuf = curwin->w_buffer;
1245       prevwin = win_find_by_handle(aco->save_prevwin_handle);
1246       // In case the autocommand moves the cursor to a position that does not
1247       // exist in curbuf
1248       check_cursor();
1249     }
1250   }
1251 }
1252 
1253 /// Execute autocommands for "event" and file name "fname".
1254 ///
1255 /// @param event event that occurred
1256 /// @param fname filename, NULL or empty means use actual file name
1257 /// @param fname_io filename to use for <afile> on cmdline
1258 /// @param force When true, ignore autocmd_busy
1259 /// @param buf Buffer for <abuf>
1260 ///
1261 /// @return true if some commands were executed.
apply_autocmds(event_T event,char_u * fname,char_u * fname_io,bool force,buf_T * buf)1262 bool apply_autocmds(event_T event, char_u *fname, char_u *fname_io, bool force, buf_T *buf)
1263 {
1264   return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf,
1265                               NULL);
1266 }
1267 
1268 /// Like apply_autocmds(), but with extra "eap" argument.  This takes care of
1269 /// setting v:filearg.
1270 ///
1271 /// @param event event that occurred
1272 /// @param fname NULL or empty means use actual file name
1273 /// @param fname_io fname to use for <afile> on cmdline
1274 /// @param force When true, ignore autocmd_busy
1275 /// @param buf Buffer for <abuf>
1276 /// @param exarg Ex command arguments
1277 ///
1278 /// @return true if some commands were executed.
apply_autocmds_exarg(event_T event,char_u * fname,char_u * fname_io,bool force,buf_T * buf,exarg_T * eap)1279 bool apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io, bool force, buf_T *buf,
1280                           exarg_T *eap)
1281 {
1282   return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf,
1283                               eap);
1284 }
1285 
1286 /// Like apply_autocmds(), but handles the caller's retval.  If the script
1287 /// processing is being aborted or if retval is FAIL when inside a try
1288 /// conditional, no autocommands are executed.  If otherwise the autocommands
1289 /// cause the script to be aborted, retval is set to FAIL.
1290 ///
1291 /// @param event event that occurred
1292 /// @param fname NULL or empty means use actual file name
1293 /// @param fname_io fname to use for <afile> on cmdline
1294 /// @param force When true, ignore autocmd_busy
1295 /// @param buf Buffer for <abuf>
1296 /// @param[in,out] retval caller's retval
1297 ///
1298 /// @return true if some autocommands were executed
apply_autocmds_retval(event_T event,char_u * fname,char_u * fname_io,bool force,buf_T * buf,int * retval)1299 bool apply_autocmds_retval(event_T event, char_u *fname, char_u *fname_io, bool force, buf_T *buf,
1300                            int *retval)
1301 {
1302   if (should_abort(*retval)) {
1303     return false;
1304   }
1305 
1306   bool did_cmd = apply_autocmds_group(event, fname, fname_io, force,
1307                                       AUGROUP_ALL, buf, NULL);
1308   if (did_cmd && aborting()) {
1309     *retval = FAIL;
1310   }
1311   return did_cmd;
1312 }
1313 
1314 /// Return true if "event" autocommand is defined.
1315 ///
1316 /// @param event the autocommand to check
has_event(event_T event)1317 bool has_event(event_T event) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
1318 {
1319   return first_autopat[event] != NULL;
1320 }
1321 
1322 /// Return true when there is a CursorHold/CursorHoldI autocommand defined for
1323 /// the current mode.
has_cursorhold(void)1324 bool has_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
1325 {
1326   return has_event((get_real_state() == NORMAL_BUSY ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI));
1327   // return first_autopat[] != NULL;
1328 }
1329 
1330 /// Return true if the CursorHold/CursorHoldI event can be triggered.
trigger_cursorhold(void)1331 bool trigger_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
1332 {
1333   int state;
1334 
1335   if (!did_cursorhold && has_cursorhold() && reg_recording == 0
1336       && typebuf.tb_len == 0 && !ins_compl_active()) {
1337     state = get_real_state();
1338     if (state == NORMAL_BUSY || (state & INSERT) != 0) {
1339       return true;
1340     }
1341   }
1342   return false;
1343 }
1344 
1345 /// Execute autocommands for "event" and file name "fname".
1346 ///
1347 /// @param event event that occurred
1348 /// @param fname filename, NULL or empty means use actual file name
1349 /// @param fname_io filename to use for <afile> on cmdline,
1350 ///                 NULL means use `fname`.
1351 /// @param force When true, ignore autocmd_busy
1352 /// @param group autocmd group ID or AUGROUP_ALL
1353 /// @param buf Buffer for <abuf>
1354 /// @param eap Ex command arguments
1355 ///
1356 /// @return true if some commands were executed.
apply_autocmds_group(event_T event,char_u * fname,char_u * fname_io,bool force,int group,buf_T * buf,exarg_T * eap)1357 static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, bool force,
1358                                  int group, buf_T *buf, exarg_T *eap)
1359 {
1360   char_u *sfname = NULL;  // short file name
1361   char_u *tail;
1362   bool save_changed;
1363   buf_T *old_curbuf;
1364   bool retval = false;
1365   char_u *save_sourcing_name;
1366   linenr_T save_sourcing_lnum;
1367   char_u *save_autocmd_fname;
1368   int save_autocmd_bufnr;
1369   char_u *save_autocmd_match;
1370   int save_autocmd_busy;
1371   int save_autocmd_nested;
1372   static int nesting = 0;
1373   AutoPatCmd patcmd;
1374   AutoPat *ap;
1375   char_u *save_cmdarg;
1376   long save_cmdbang;
1377   static int filechangeshell_busy = false;
1378   proftime_T wait_time;
1379   bool did_save_redobuff = false;
1380   save_redo_T save_redo;
1381   const bool save_KeyTyped = KeyTyped;
1382 
1383   // Quickly return if there are no autocommands for this event or
1384   // autocommands are blocked.
1385   if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
1386       || is_autocmd_blocked()) {
1387     goto BYPASS_AU;
1388   }
1389 
1390   // When autocommands are busy, new autocommands are only executed when
1391   // explicitly enabled with the "nested" flag.
1392   if (autocmd_busy && !(force || autocmd_nested)) {
1393     goto BYPASS_AU;
1394   }
1395 
1396   // Quickly return when immediately aborting on error, or when an interrupt
1397   // occurred or an exception was thrown but not caught.
1398   if (aborting()) {
1399     goto BYPASS_AU;
1400   }
1401 
1402   // FileChangedShell never nests, because it can create an endless loop.
1403   if (filechangeshell_busy
1404       && (event == EVENT_FILECHANGEDSHELL
1405           || event == EVENT_FILECHANGEDSHELLPOST)) {
1406     goto BYPASS_AU;
1407   }
1408 
1409   // Ignore events in 'eventignore'.
1410   if (event_ignored(event)) {
1411     goto BYPASS_AU;
1412   }
1413 
1414   // Allow nesting of autocommands, but restrict the depth, because it's
1415   // possible to create an endless loop.
1416   if (nesting == 10) {
1417     emsg(_("E218: autocommand nesting too deep"));
1418     goto BYPASS_AU;
1419   }
1420 
1421   // Check if these autocommands are disabled.  Used when doing ":all" or
1422   // ":ball".
1423   if ((autocmd_no_enter && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
1424       || (autocmd_no_leave
1425           && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE))) {
1426     goto BYPASS_AU;
1427   }
1428 
1429   // Save the autocmd_* variables and info about the current buffer.
1430   save_autocmd_fname = autocmd_fname;
1431   save_autocmd_bufnr = autocmd_bufnr;
1432   save_autocmd_match = autocmd_match;
1433   save_autocmd_busy = autocmd_busy;
1434   save_autocmd_nested = autocmd_nested;
1435   save_changed = curbuf->b_changed;
1436   old_curbuf = curbuf;
1437 
1438   // Set the file name to be used for <afile>.
1439   // Make a copy to avoid that changing a buffer name or directory makes it
1440   // invalid.
1441   if (fname_io == NULL) {
1442     if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
1443         || event == EVENT_OPTIONSET) {
1444       autocmd_fname = NULL;
1445     } else if (fname != NULL && !ends_excmd(*fname)) {
1446       autocmd_fname = fname;
1447     } else if (buf != NULL) {
1448       autocmd_fname = buf->b_ffname;
1449     } else {
1450       autocmd_fname = NULL;
1451     }
1452   } else {
1453     autocmd_fname = fname_io;
1454   }
1455   if (autocmd_fname != NULL) {
1456     // Allocate MAXPATHL for when eval_vars() resolves the fullpath.
1457     autocmd_fname = vim_strnsave(autocmd_fname, MAXPATHL);
1458   }
1459 
1460   // Set the buffer number to be used for <abuf>.
1461   if (buf == NULL) {
1462     autocmd_bufnr = 0;
1463   } else {
1464     autocmd_bufnr = buf->b_fnum;
1465   }
1466 
1467   // When the file name is NULL or empty, use the file name of buffer "buf".
1468   // Always use the full path of the file name to match with, in case
1469   // "allow_dirs" is set.
1470   if (fname == NULL || *fname == NUL) {
1471     if (buf == NULL) {
1472       fname = NULL;
1473     } else {
1474       if (event == EVENT_SYNTAX) {
1475         fname = buf->b_p_syn;
1476       } else if (event == EVENT_FILETYPE) {
1477         fname = buf->b_p_ft;
1478       } else {
1479         if (buf->b_sfname != NULL) {
1480           sfname = vim_strsave(buf->b_sfname);
1481         }
1482         fname = buf->b_ffname;
1483       }
1484     }
1485     if (fname == NULL) {
1486       fname = (char_u *)"";
1487     }
1488     fname = vim_strsave(fname);  // make a copy, so we can change it
1489   } else {
1490     sfname = vim_strsave(fname);
1491     // Don't try expanding the following events.
1492     if (event == EVENT_CMDLINECHANGED || event == EVENT_CMDLINEENTER
1493         || event == EVENT_CMDLINELEAVE || event == EVENT_CMDWINENTER
1494         || event == EVENT_CMDWINLEAVE || event == EVENT_CMDUNDEFINED
1495         || event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
1496         || event == EVENT_DIRCHANGED || event == EVENT_FILETYPE
1497         || event == EVENT_FUNCUNDEFINED || event == EVENT_OPTIONSET
1498         || event == EVENT_QUICKFIXCMDPOST || event == EVENT_QUICKFIXCMDPRE
1499         || event == EVENT_REMOTEREPLY || event == EVENT_SPELLFILEMISSING
1500         || event == EVENT_SYNTAX || event == EVENT_SIGNAL
1501         || event == EVENT_TABCLOSED || event == EVENT_WINCLOSED) {
1502       fname = vim_strsave(fname);
1503     } else {
1504       fname = (char_u *)FullName_save((char *)fname, false);
1505     }
1506   }
1507   if (fname == NULL) {  // out of memory
1508     xfree(sfname);
1509     retval = false;
1510     goto BYPASS_AU;
1511   }
1512 
1513 #ifdef BACKSLASH_IN_FILENAME
1514   // Replace all backslashes with forward slashes. This makes the
1515   // autocommand patterns portable between Unix and Windows.
1516   if (sfname != NULL) {
1517     forward_slash(sfname);
1518   }
1519   forward_slash(fname);
1520 #endif
1521 
1522   // Set the name to be used for <amatch>.
1523   autocmd_match = fname;
1524 
1525   // Don't redraw while doing autocommands.
1526   RedrawingDisabled++;
1527   save_sourcing_name = sourcing_name;
1528   sourcing_name = NULL;  // don't free this one
1529   save_sourcing_lnum = sourcing_lnum;
1530   sourcing_lnum = 0;  // no line number here
1531 
1532   const sctx_T save_current_sctx = current_sctx;
1533 
1534   if (do_profiling == PROF_YES) {
1535     prof_child_enter(&wait_time);  // doesn't count for the caller itself
1536   }
1537 
1538   // Don't use local function variables, if called from a function.
1539   funccal_entry_T funccal_entry;
1540   save_funccal(&funccal_entry);
1541 
1542   // When starting to execute autocommands, save the search patterns.
1543   if (!autocmd_busy) {
1544     save_search_patterns();
1545     if (!ins_compl_active()) {
1546       saveRedobuff(&save_redo);
1547       did_save_redobuff = true;
1548     }
1549     did_filetype = keep_filetype;
1550   }
1551 
1552   // Note that we are applying autocmds.  Some commands need to know.
1553   autocmd_busy = true;
1554   filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
1555   nesting++;  // see matching decrement below
1556 
1557   // Remember that FileType was triggered.  Used for did_filetype().
1558   if (event == EVENT_FILETYPE) {
1559     did_filetype = true;
1560   }
1561 
1562   tail = path_tail(fname);
1563 
1564   // Find first autocommand that matches
1565   patcmd.curpat = first_autopat[(int)event];
1566   patcmd.nextcmd = NULL;
1567   patcmd.group = group;
1568   patcmd.fname = fname;
1569   patcmd.sfname = sfname;
1570   patcmd.tail = tail;
1571   patcmd.event = event;
1572   patcmd.arg_bufnr = autocmd_bufnr;
1573   patcmd.next = NULL;
1574   auto_next_pat(&patcmd, false);
1575 
1576   // found one, start executing the autocommands
1577   if (patcmd.curpat != NULL) {
1578     // add to active_apc_list
1579     patcmd.next = active_apc_list;
1580     active_apc_list = &patcmd;
1581 
1582     // set v:cmdarg (only when there is a matching pattern)
1583     save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
1584     if (eap != NULL) {
1585       save_cmdarg = set_cmdarg(eap, NULL);
1586       set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
1587     } else {
1588       save_cmdarg = NULL;  // avoid gcc warning
1589     }
1590     retval = true;
1591     // mark the last pattern, to avoid an endless loop when more patterns
1592     // are added when executing autocommands
1593     for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next) {
1594       ap->last = false;
1595     }
1596     ap->last = true;
1597 
1598     if (nesting == 1) {
1599       // make sure cursor and topline are valid
1600       check_lnums(true);
1601     }
1602 
1603     // Execute the autocmd. The `getnextac` callback handles iteration.
1604     do_cmdline(NULL, getnextac, (void *)&patcmd,
1605                DOCMD_NOWAIT | DOCMD_VERBOSE | DOCMD_REPEAT);
1606 
1607     if (nesting == 1) {
1608       // restore cursor and topline, unless they were changed
1609       reset_lnums();
1610     }
1611 
1612 
1613     if (eap != NULL) {
1614       (void)set_cmdarg(NULL, save_cmdarg);
1615       set_vim_var_nr(VV_CMDBANG, save_cmdbang);
1616     }
1617     // delete from active_apc_list
1618     if (active_apc_list == &patcmd) {  // just in case
1619       active_apc_list = patcmd.next;
1620     }
1621   }
1622 
1623   RedrawingDisabled--;
1624   autocmd_busy = save_autocmd_busy;
1625   filechangeshell_busy = false;
1626   autocmd_nested = save_autocmd_nested;
1627   xfree(sourcing_name);
1628   sourcing_name = save_sourcing_name;
1629   sourcing_lnum = save_sourcing_lnum;
1630   xfree(autocmd_fname);
1631   autocmd_fname = save_autocmd_fname;
1632   autocmd_bufnr = save_autocmd_bufnr;
1633   autocmd_match = save_autocmd_match;
1634   current_sctx = save_current_sctx;
1635   restore_funccal();
1636   if (do_profiling == PROF_YES) {
1637     prof_child_exit(&wait_time);
1638   }
1639   KeyTyped = save_KeyTyped;
1640   xfree(fname);
1641   xfree(sfname);
1642   nesting--;  // see matching increment above
1643 
1644   // When stopping to execute autocommands, restore the search patterns and
1645   // the redo buffer. Free any buffers in the au_pending_free_buf list and
1646   // free any windows in the au_pending_free_win list.
1647   if (!autocmd_busy) {
1648     restore_search_patterns();
1649     if (did_save_redobuff) {
1650       restoreRedobuff(&save_redo);
1651     }
1652     did_filetype = false;
1653     while (au_pending_free_buf != NULL) {
1654       buf_T *b = au_pending_free_buf->b_next;
1655 
1656       xfree(au_pending_free_buf);
1657       au_pending_free_buf = b;
1658     }
1659     while (au_pending_free_win != NULL) {
1660       win_T *w = au_pending_free_win->w_next;
1661 
1662       xfree(au_pending_free_win);
1663       au_pending_free_win = w;
1664     }
1665   }
1666 
1667   // Some events don't set or reset the Changed flag.
1668   // Check if still in the same buffer!
1669   if (curbuf == old_curbuf
1670       && (event == EVENT_BUFREADPOST || event == EVENT_BUFWRITEPOST
1671           || event == EVENT_FILEAPPENDPOST || event == EVENT_VIMLEAVE
1672           || event == EVENT_VIMLEAVEPRE)) {
1673     if (curbuf->b_changed != save_changed) {
1674       need_maketitle = true;
1675     }
1676     curbuf->b_changed = save_changed;
1677   }
1678 
1679   au_cleanup();  // may really delete removed patterns/commands now
1680 
1681 BYPASS_AU:
1682   // When wiping out a buffer make sure all its buffer-local autocommands
1683   // are deleted.
1684   if (event == EVENT_BUFWIPEOUT && buf != NULL) {
1685     aubuflocal_remove(buf);
1686   }
1687 
1688   if (retval == OK && event == EVENT_FILETYPE) {
1689     au_did_filetype = true;
1690   }
1691 
1692   return retval;
1693 }
1694 
1695 // Block triggering autocommands until unblock_autocmd() is called.
1696 // Can be used recursively, so long as it's symmetric.
block_autocmds(void)1697 void block_autocmds(void)
1698 {
1699   // Remember the value of v:termresponse.
1700   if (!is_autocmd_blocked()) {
1701     old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
1702   }
1703   autocmd_blocked++;
1704 }
1705 
unblock_autocmds(void)1706 void unblock_autocmds(void)
1707 {
1708   autocmd_blocked--;
1709 
1710   // When v:termresponse was set while autocommands were blocked, trigger
1711   // the autocommands now.  Esp. useful when executing a shell command
1712   // during startup (nvim -d).
1713   if (!is_autocmd_blocked()
1714       && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse) {
1715     apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, false, curbuf);
1716   }
1717 }
1718 
is_autocmd_blocked(void)1719 bool is_autocmd_blocked(void)
1720   FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
1721 {
1722   return autocmd_blocked != 0;
1723 }
1724 
1725 /// Find next autocommand pattern that matches.
1726 /// stop when 'last' flag is set
auto_next_pat(AutoPatCmd * apc,int stop_at_last)1727 void auto_next_pat(AutoPatCmd *apc, int stop_at_last)
1728 {
1729   AutoPat *ap;
1730   AutoCmd *cp;
1731   char *s;
1732 
1733   XFREE_CLEAR(sourcing_name);
1734 
1735   for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next) {
1736     apc->curpat = NULL;
1737 
1738     // Only use a pattern when it has not been removed, has commands and
1739     // the group matches. For buffer-local autocommands only check the
1740     // buffer number.
1741     if (ap->pat != NULL && ap->cmds != NULL
1742         && (apc->group == AUGROUP_ALL || apc->group == ap->group)) {
1743       // execution-condition
1744       if (ap->buflocal_nr == 0
1745           ? match_file_pat(NULL,
1746                            &ap->reg_prog,
1747                            apc->fname,
1748                            apc->sfname,
1749                            apc->tail,
1750                            ap->allow_dirs)
1751           : ap->buflocal_nr == apc->arg_bufnr) {
1752         const char *const name = event_nr2name(apc->event);
1753         s = _("%s Autocommands for \"%s\"");
1754 
1755         const size_t sourcing_name_len
1756           = (STRLEN(s) + strlen(name) + (size_t)ap->patlen + 1);
1757 
1758         sourcing_name = xmalloc(sourcing_name_len);
1759         snprintf((char *)sourcing_name, sourcing_name_len, s, name,
1760                  (char *)ap->pat);
1761         if (p_verbose >= 8) {
1762           verbose_enter();
1763           smsg(_("Executing %s"), sourcing_name);
1764           verbose_leave();
1765         }
1766 
1767         apc->curpat = ap;
1768         apc->nextcmd = ap->cmds;
1769         // mark last command
1770         for (cp = ap->cmds; cp->next != NULL; cp = cp->next) {
1771           cp->last = false;
1772         }
1773         cp->last = true;
1774       }
1775       line_breakcheck();
1776       if (apc->curpat != NULL) {  // found a match
1777         break;
1778       }
1779     }
1780     if (stop_at_last && ap->last) {
1781       break;
1782     }
1783   }
1784 }
1785 
1786 /// Get next autocommand command.
1787 /// Called by do_cmdline() to get the next line for ":if".
1788 /// @return allocated string, or NULL for end of autocommands.
getnextac(int c,void * cookie,int indent,bool do_concat)1789 char_u *getnextac(int c, void *cookie, int indent, bool do_concat)
1790 {
1791   AutoPatCmd *acp = (AutoPatCmd *)cookie;
1792   char_u *retval;
1793   AutoCmd *ac;
1794 
1795   // Can be called again after returning the last line.
1796   if (acp->curpat == NULL) {
1797     return NULL;
1798   }
1799 
1800   // repeat until we find an autocommand to execute
1801   for (;;) {
1802     // skip removed commands
1803     while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL) {
1804       if (acp->nextcmd->last) {
1805         acp->nextcmd = NULL;
1806       } else {
1807         acp->nextcmd = acp->nextcmd->next;
1808       }
1809     }
1810 
1811     if (acp->nextcmd != NULL) {
1812       break;
1813     }
1814 
1815     // at end of commands, find next pattern that matches
1816     if (acp->curpat->last) {
1817       acp->curpat = NULL;
1818     } else {
1819       acp->curpat = acp->curpat->next;
1820     }
1821     if (acp->curpat != NULL) {
1822       auto_next_pat(acp, true);
1823     }
1824     if (acp->curpat == NULL) {
1825       return NULL;
1826     }
1827   }
1828 
1829   ac = acp->nextcmd;
1830 
1831   if (p_verbose >= 9) {
1832     verbose_enter_scroll();
1833     smsg(_("autocommand %s"), ac->cmd);
1834     msg_puts("\n");  // don't overwrite this either
1835     verbose_leave_scroll();
1836   }
1837   retval = vim_strsave(ac->cmd);
1838   // Remove one-shot ("once") autocmd in anticipation of its execution.
1839   if (ac->once) {
1840     au_del_cmd(ac);
1841   }
1842   autocmd_nested = ac->nested;
1843   current_sctx = ac->script_ctx;
1844   if (ac->last) {
1845     acp->nextcmd = NULL;
1846   } else {
1847     acp->nextcmd = ac->next;
1848   }
1849 
1850   return retval;
1851 }
1852 
1853 /// Return true if there is a matching autocommand for "fname".
1854 /// To account for buffer-local autocommands, function needs to know
1855 /// in which buffer the file will be opened.
1856 ///
1857 /// @param event event that occurred.
1858 /// @param sfname filename the event occurred in.
1859 /// @param buf buffer the file is open in
has_autocmd(event_T event,char_u * sfname,buf_T * buf)1860 bool has_autocmd(event_T event, char_u *sfname, buf_T *buf) FUNC_ATTR_WARN_UNUSED_RESULT
1861 {
1862   AutoPat *ap;
1863   char_u *fname;
1864   char_u *tail = path_tail(sfname);
1865   bool retval = false;
1866 
1867   fname = (char_u *)FullName_save((char *)sfname, false);
1868   if (fname == NULL) {
1869     return false;
1870   }
1871 
1872 #ifdef BACKSLASH_IN_FILENAME
1873   // Replace all backslashes with forward slashes. This makes the
1874   // autocommand patterns portable between Unix and Windows.
1875   sfname = vim_strsave(sfname);
1876   forward_slash(sfname);
1877   forward_slash(fname);
1878 #endif
1879 
1880   for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) {
1881     if (ap->pat != NULL && ap->cmds != NULL
1882         && (ap->buflocal_nr == 0
1883             ? match_file_pat(NULL,
1884                              &ap->reg_prog,
1885                              fname,
1886                              sfname,
1887                              tail,
1888                              ap->allow_dirs)
1889             : buf != NULL && ap->buflocal_nr == buf->b_fnum)) {
1890       retval = true;
1891       break;
1892     }
1893   }
1894 
1895   xfree(fname);
1896 #ifdef BACKSLASH_IN_FILENAME
1897   xfree(sfname);
1898 #endif
1899 
1900   return retval;
1901 }
1902 
1903 // Function given to ExpandGeneric() to obtain the list of autocommand group
1904 // names.
get_augroup_name(expand_T * xp,int idx)1905 char_u *get_augroup_name(expand_T *xp, int idx)
1906 {
1907   if (idx == augroups.ga_len) {  // add "END" add the end
1908     return (char_u *)"END";
1909   }
1910   if (idx >= augroups.ga_len) {  // end of list
1911     return NULL;
1912   }
1913   if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup()) {
1914     // skip deleted entries
1915     return (char_u *)"";
1916   }
1917   return (char_u *)AUGROUP_NAME(idx);
1918 }
1919 
1920 /// @param doautocmd  true for :doauto*, false for :autocmd
set_context_in_autocmd(expand_T * xp,char_u * arg,int doautocmd)1921 char_u *set_context_in_autocmd(expand_T *xp, char_u *arg, int doautocmd)
1922 {
1923   char_u *p;
1924   int group;
1925 
1926   // check for a group name, skip it if present
1927   autocmd_include_groups = false;
1928   p = arg;
1929   group = au_get_grouparg(&arg);
1930 
1931   // If there only is a group name that's what we expand.
1932   if (*arg == NUL && group != AUGROUP_ALL && !ascii_iswhite(arg[-1])) {
1933     arg = p;
1934     group = AUGROUP_ALL;
1935   }
1936 
1937   // skip over event name
1938   for (p = arg; *p != NUL && !ascii_iswhite(*p); p++) {
1939     if (*p == ',') {
1940       arg = p + 1;
1941     }
1942   }
1943   if (*p == NUL) {
1944     if (group == AUGROUP_ALL) {
1945       autocmd_include_groups = true;
1946     }
1947     xp->xp_context = EXPAND_EVENTS;  // expand event name
1948     xp->xp_pattern = arg;
1949     return NULL;
1950   }
1951 
1952   // skip over pattern
1953   arg = skipwhite(p);
1954   while (*arg && (!ascii_iswhite(*arg) || arg[-1] == '\\')) {
1955     arg++;
1956   }
1957   if (*arg) {
1958     return arg;  // expand (next) command
1959   }
1960 
1961   if (doautocmd) {
1962     xp->xp_context = EXPAND_FILES;  // expand file names
1963   } else {
1964     xp->xp_context = EXPAND_NOTHING;  // pattern is not expanded
1965   }
1966   return NULL;
1967 }
1968 
1969 // Function given to ExpandGeneric() to obtain the list of event names.
get_event_name(expand_T * xp,int idx)1970 char_u *get_event_name(expand_T *xp, int idx)
1971 {
1972   if (idx < augroups.ga_len) {  // First list group names, if wanted
1973     if (!autocmd_include_groups || AUGROUP_NAME(idx) == NULL
1974         || AUGROUP_NAME(idx) == get_deleted_augroup()) {
1975       return (char_u *)"";  // skip deleted entries
1976     }
1977     return (char_u *)AUGROUP_NAME(idx);
1978   }
1979   return (char_u *)event_names[idx - augroups.ga_len].name;
1980 }
1981 
1982 /// Check whether given autocommand is supported
1983 ///
1984 /// @param[in]  event  Event to check.
1985 ///
1986 /// @return True if it is, false otherwise.
autocmd_supported(const char * const event)1987 bool autocmd_supported(const char *const event)
1988   FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
1989 {
1990   char_u *p;
1991   return event_name2nr((const char_u *)event, &p) != NUM_EVENTS;
1992 }
1993 
1994 /// Return true if an autocommand is defined for a group, event and
1995 /// pattern:  The group can be omitted to accept any group.
1996 /// `event` and `pattern` can be omitted to accept any event and pattern.
1997 /// Buffer-local patterns <buffer> or <buffer=N> are accepted.
1998 /// Used for:
1999 ///   exists("#Group") or
2000 ///   exists("#Group#Event") or
2001 ///   exists("#Group#Event#pat") or
2002 ///   exists("#Event") or
2003 ///   exists("#Event#pat")
2004 ///
2005 /// @param arg autocommand string
au_exists(const char * const arg)2006 bool au_exists(const char *const arg) FUNC_ATTR_WARN_UNUSED_RESULT
2007 {
2008   event_T event;
2009   AutoPat *ap;
2010   buf_T *buflocal_buf = NULL;
2011   int group;
2012   bool retval = false;
2013 
2014   // Make a copy so that we can change the '#' chars to a NUL.
2015   char *const arg_save = xstrdup(arg);
2016   char *p = strchr(arg_save, '#');
2017   if (p != NULL) {
2018     *p++ = NUL;
2019   }
2020 
2021   // First, look for an autocmd group name.
2022   group = au_find_group((char_u *)arg_save);
2023   char *event_name;
2024   if (group == AUGROUP_ERROR) {
2025     // Didn't match a group name, assume the first argument is an event.
2026     group = AUGROUP_ALL;
2027     event_name = arg_save;
2028   } else {
2029     if (p == NULL) {
2030       // "Group": group name is present and it's recognized
2031       retval = true;
2032       goto theend;
2033     }
2034 
2035     // Must be "Group#Event" or "Group#Event#pat".
2036     event_name = p;
2037     p = strchr(event_name, '#');
2038     if (p != NULL) {
2039       *p++ = NUL;  // "Group#Event#pat"
2040     }
2041   }
2042 
2043   char *pattern = p;  // "pattern" is NULL when there is no pattern.
2044 
2045   // Find the index (enum) for the event name.
2046   event = event_name2nr((char_u *)event_name, (char_u **)&p);
2047 
2048   // return false if the event name is not recognized
2049   if (event == NUM_EVENTS) {
2050     goto theend;
2051   }
2052 
2053   // Find the first autocommand for this event.
2054   // If there isn't any, return false;
2055   // If there is one and no pattern given, return true;
2056   ap = first_autopat[(int)event];
2057   if (ap == NULL) {
2058     goto theend;
2059   }
2060 
2061   // if pattern is "<buffer>", special handling is needed which uses curbuf
2062   // for pattern "<buffer=N>, fnamecmp() will work fine
2063   if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0) {
2064     buflocal_buf = curbuf;
2065   }
2066 
2067   // Check if there is an autocommand with the given pattern.
2068   for (; ap != NULL; ap = ap->next) {
2069     // only use a pattern when it has not been removed and has commands.
2070     // For buffer-local autocommands, fnamecmp() works fine.
2071     if (ap->pat != NULL && ap->cmds != NULL
2072         && (group == AUGROUP_ALL || ap->group == group)
2073         && (pattern == NULL
2074             || (buflocal_buf == NULL
2075                 ? fnamecmp(ap->pat, (char_u *)pattern) == 0
2076                 : ap->buflocal_nr == buflocal_buf->b_fnum))) {
2077       retval = true;
2078       break;
2079     }
2080   }
2081 
2082 theend:
2083   xfree(arg_save);
2084   return retval;
2085 }
2086