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/*
5 * quickfix.c: functions for quickfix mode, using a file with error messages
6 */
7
8#include <assert.h>
9#include <inttypes.h>
10#include <stdbool.h>
11#include <string.h>
12
13#include "nvim/vim.h"
14#include "nvim/ascii.h"
15#include "nvim/quickfix.h"
16#include "nvim/buffer.h"
17#include "nvim/charset.h"
18#include "nvim/cursor.h"
19#include "nvim/edit.h"
20#include "nvim/eval.h"
21#include "nvim/ex_cmds.h"
22#include "nvim/ex_cmds2.h"
23#include "nvim/ex_docmd.h"
24#include "nvim/ex_eval.h"
25#include "nvim/ex_getln.h"
26#include "nvim/fileio.h"
27#include "nvim/fold.h"
28#include "nvim/mark.h"
29#include "nvim/mbyte.h"
30#include "nvim/memline.h"
31#include "nvim/message.h"
32#include "nvim/misc1.h"
33#include "nvim/memory.h"
34#include "nvim/move.h"
35#include "nvim/normal.h"
36#include "nvim/option.h"
37#include "nvim/os_unix.h"
38#include "nvim/path.h"
39#include "nvim/regexp.h"
40#include "nvim/screen.h"
41#include "nvim/search.h"
42#include "nvim/strings.h"
43#include "nvim/syntax.h"
44#include "nvim/ui.h"
45#include "nvim/window.h"
46#include "nvim/os/os.h"
47#include "nvim/os/input.h"
48#include "nvim/api/private/helpers.h"
49
50
51struct dir_stack_T {
52 struct dir_stack_T *next;
53 char_u *dirname;
54};
55
56/*
57 * For each error the next struct is allocated and linked in a list.
58 */
59typedef struct qfline_S qfline_T;
60struct qfline_S {
61 qfline_T *qf_next; ///< pointer to next error in the list
62 qfline_T *qf_prev; ///< pointer to previous error in the list
63 linenr_T qf_lnum; ///< line number where the error occurred
64 int qf_fnum; ///< file number for the line
65 int qf_col; ///< column where the error occurred
66 int qf_nr; ///< error number
67 char_u *qf_module; ///< module name for this error
68 char_u *qf_pattern; ///< search pattern for the error
69 char_u *qf_text; ///< description of the error
70 char_u qf_viscol; ///< set to TRUE if qf_col is screen column
71 char_u qf_cleared; ///< set to TRUE if line has been deleted
72 char_u qf_type; ///< type of the error (mostly 'E'); 1 for
73 // :helpgrep
74 char_u qf_valid; ///< valid error message detected
75};
76
77/*
78 * There is a stack of error lists.
79 */
80#define LISTCOUNT 10
81#define INVALID_QFIDX (-1)
82
83/// Quickfix/Location list definition
84///
85/// Usually the list contains one or more entries. But an empty list can be
86/// created using setqflist()/setloclist() with a title and/or user context
87/// information and entries can be added later using setqflist()/setloclist().
88typedef struct qf_list_S {
89 unsigned qf_id; ///< Unique identifier for this list
90 qfline_T *qf_start; ///< pointer to the first error
91 qfline_T *qf_last; ///< pointer to the last error
92 qfline_T *qf_ptr; ///< pointer to the current error
93 int qf_count; ///< number of errors (0 means empty list)
94 int qf_index; ///< current index in the error list
95 int qf_nonevalid; ///< TRUE if not a single valid entry found
96 char_u *qf_title; ///< title derived from the command that created
97 ///< the error list or set by setqflist
98 typval_T *qf_ctx; ///< context set by setqflist/setloclist
99
100 struct dir_stack_T *qf_dir_stack;
101 char_u *qf_directory;
102 struct dir_stack_T *qf_file_stack;
103 char_u *qf_currfile;
104 bool qf_multiline;
105 bool qf_multiignore;
106 bool qf_multiscan;
107 long qf_changedtick;
108} qf_list_T;
109
110/// Quickfix/Location list stack definition
111/// Contains a list of quickfix/location lists (qf_list_T)
112struct qf_info_S {
113 /*
114 * Count of references to this list. Used only for location lists.
115 * When a location list window reference this list, qf_refcount
116 * will be 2. Otherwise, qf_refcount will be 1. When qf_refcount
117 * reaches 0, the list is freed.
118 */
119 int qf_refcount;
120 int qf_listcount; /* current number of lists */
121 int qf_curlist; /* current error list */
122 qf_list_T qf_lists[LISTCOUNT];
123};
124
125static qf_info_T ql_info; // global quickfix list
126static unsigned last_qf_id = 0; // Last Used quickfix list id
127
128#define FMT_PATTERNS 11 // maximum number of % recognized
129
130/*
131 * Structure used to hold the info of one part of 'errorformat'
132 */
133typedef struct efm_S efm_T;
134struct efm_S {
135 regprog_T *prog; /* pre-formatted part of 'errorformat' */
136 efm_T *next; /* pointer to next (NULL if last) */
137 char_u addr[FMT_PATTERNS]; /* indices of used % patterns */
138 char_u prefix; /* prefix of this format line: */
139 /* 'D' enter directory */
140 /* 'X' leave directory */
141 /* 'A' start of multi-line message */
142 /* 'E' error message */
143 /* 'W' warning message */
144 /* 'I' informational message */
145 /* 'C' continuation line */
146 /* 'Z' end of multi-line message */
147 /* 'G' general, unspecific message */
148 /* 'P' push file (partial) message */
149 /* 'Q' pop/quit file (partial) message */
150 /* 'O' overread (partial) message */
151 char_u flags; /* additional flags given in prefix */
152 /* '-' do not include this line */
153 /* '+' include whole line in message */
154 int conthere; /* %> used */
155};
156
157enum {
158 QF_FAIL = 0,
159 QF_OK = 1,
160 QF_END_OF_INPUT = 2,
161 QF_NOMEM = 3,
162 QF_IGNORE_LINE = 4,
163 QF_MULTISCAN = 5,
164};
165
166typedef struct {
167 char_u *linebuf;
168 size_t linelen;
169 char_u *growbuf;
170 size_t growbufsiz;
171 FILE *fd;
172 typval_T *tv;
173 char_u *p_str;
174 list_T *p_list;
175 listitem_T *p_li;
176 buf_T *buf;
177 linenr_T buflnum;
178 linenr_T lnumlast;
179 vimconv_T vc;
180} qfstate_T;
181
182typedef struct {
183 char_u *namebuf;
184 char_u *module;
185 char_u *errmsg;
186 size_t errmsglen;
187 long lnum;
188 int col;
189 bool use_viscol;
190 char_u *pattern;
191 int enr;
192 char_u type;
193 bool valid;
194} qffields_T;
195
196#ifdef INCLUDE_GENERATED_DECLARATIONS
197# include "quickfix.c.generated.h"
198#endif
199/* Quickfix window check helper macro */
200#define IS_QF_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref == NULL)
201/* Location list window check helper macro */
202#define IS_LL_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL)
203
204// Quickfix and location list stack check helper macros
205#define IS_QF_STACK(qi) (qi == &ql_info)
206#define IS_LL_STACK(qi) (qi != &ql_info)
207
208//
209// Return location list for window 'wp'
210// For location list window, return the referenced location list
211//
212#define GET_LOC_LIST(wp) (IS_LL_WINDOW(wp) ? wp->w_llist_ref : wp->w_llist)
213
214// Looking up a buffer can be slow if there are many. Remember the last one
215// to make this a lot faster if there are multiple matches in the same file.
216static char_u *qf_last_bufname = NULL;
217static bufref_T qf_last_bufref = { NULL, 0, 0 };
218
219static char *e_loc_list_changed = N_("E926: Current location list was changed");
220
221/// Read the errorfile "efile" into memory, line by line, building the error
222/// list. Set the error list's title to qf_title.
223///
224/// @params wp If non-NULL, make a location list
225/// @params efile If non-NULL, errorfile to parse
226/// @params errorformat 'errorformat' string used to parse the error lines
227/// @params newlist If true, create a new error list
228/// @params qf_title If non-NULL, title of the error list
229/// @params enc If non-NULL, encoding used to parse errors
230///
231/// @returns -1 for error, number of errors for success.
232int qf_init(win_T *wp, char_u *efile, char_u *errorformat, int newlist,
233 char_u *qf_title, char_u *enc)
234{
235 qf_info_T *qi = &ql_info;
236
237 if (wp != NULL) {
238 qi = ll_get_or_alloc_list(wp);
239 }
240
241 return qf_init_ext(qi, qi->qf_curlist, efile, curbuf, NULL, errorformat,
242 newlist, (linenr_T)0, (linenr_T)0, qf_title, enc);
243}
244
245// Maximum number of bytes allowed per line while reading an errorfile.
246static const size_t LINE_MAXLEN = 4096;
247
248static struct fmtpattern
249{
250 char_u convchar;
251 char *pattern;
252} fmt_pat[FMT_PATTERNS] =
253{
254 { 'f', ".\\+" }, // only used when at end
255 { 'n', "\\d\\+" },
256 { 'l', "\\d\\+" },
257 { 'c', "\\d\\+" },
258 { 't', "." },
259 { 'm', ".\\+" },
260 { 'r', ".*" },
261 { 'p', "[- .]*" }, // NOLINT(whitespace/tab)
262 { 'v', "\\d\\+" },
263 { 's', ".\\+" },
264 { 'o', ".\\+" }
265};
266
267// Converts a 'errorformat' string to regular expression pattern
268static int efm_to_regpat(char_u *efm, int len, efm_T *fmt_ptr,
269 char_u *regpat, char_u *errmsg)
270{
271 // Build regexp pattern from current 'errorformat' option
272 char_u *ptr = regpat;
273 *ptr++ = '^';
274 int round = 0;
275 for (char_u *efmp = efm; efmp < efm + len; efmp++) {
276 if (*efmp == '%') {
277 efmp++;
278 int idx;
279 for (idx = 0; idx < FMT_PATTERNS; idx++) {
280 if (fmt_pat[idx].convchar == *efmp) {
281 break;
282 }
283 }
284 if (idx < FMT_PATTERNS) {
285 if (fmt_ptr->addr[idx]) {
286 snprintf((char *)errmsg, CMDBUFFSIZE + 1,
287 _("E372: Too many %%%c in format string"), *efmp);
288 EMSG(errmsg);
289 return -1;
290 }
291 if ((idx
292 && idx < 6
293 && vim_strchr((char_u *)"DXOPQ", fmt_ptr->prefix) != NULL)
294 || (idx == 6
295 && vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL)) {
296 snprintf((char *)errmsg, CMDBUFFSIZE + 1,
297 _("E373: Unexpected %%%c in format string"), *efmp);
298 EMSG(errmsg);
299 return -1;
300 }
301 round++;
302 fmt_ptr->addr[idx] = (char_u)round;
303 *ptr++ = '\\';
304 *ptr++ = '(';
305#ifdef BACKSLASH_IN_FILENAME
306 if (*efmp == 'f') {
307 // Also match "c:" in the file name, even when
308 // checking for a colon next: "%f:".
309 // "\%(\a:\)\="
310 STRCPY(ptr, "\\%(\\a:\\)\\=");
311 ptr += 10;
312 }
313#endif
314 if (*efmp == 'f' && efmp[1] != NUL) {
315 if (efmp[1] != '\\' && efmp[1] != '%') {
316 // A file name may contain spaces, but this isn't
317 // in "\f". For "%f:%l:%m" there may be a ":" in
318 // the file name. Use ".\{-1,}x" instead (x is
319 // the next character), the requirement that :999:
320 // follows should work.
321 STRCPY(ptr, ".\\{-1,}");
322 ptr += 7;
323 } else {
324 // File name followed by '\\' or '%': include as
325 // many file name chars as possible.
326 STRCPY(ptr, "\\f\\+");
327 ptr += 4;
328 }
329 } else {
330 char_u *srcptr = (char_u *)fmt_pat[idx].pattern;
331 while ((*ptr = *srcptr++) != NUL) {
332 ptr++;
333 }
334 }
335 *ptr++ = '\\';
336 *ptr++ = ')';
337 } else if (*efmp == '*') {
338 if (*++efmp == '[' || *efmp == '\\') {
339 if ((*ptr++ = *efmp) == '[') { // %*[^a-z0-9] etc.
340 if (efmp[1] == '^') {
341 *ptr++ = *++efmp;
342 }
343 if (efmp < efm + len) {
344 efmp++;
345 *ptr++ = *efmp; // could be ']'
346 while (efmp < efm + len) {
347 efmp++;
348 if ((*ptr++ = *efmp) == ']') {
349 break;
350 }
351 }
352 if (efmp == efm + len) {
353 EMSG(_("E374: Missing ] in format string"));
354 return -1;
355 }
356 }
357 } else if (efmp < efm + len) { // %*\D, %*\s etc.
358 efmp++;
359 *ptr++ = *efmp;
360 }
361 *ptr++ = '\\';
362 *ptr++ = '+';
363 } else {
364 // TODO(vim): scanf()-like: %*ud, %*3c, %*f, ... ?
365 snprintf((char *)errmsg, CMDBUFFSIZE + 1,
366 _("E375: Unsupported %%%c in format string"), *efmp);
367 EMSG(errmsg);
368 return -1;
369 }
370 } else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) {
371 *ptr++ = *efmp; // regexp magic characters
372 } else if (*efmp == '#') {
373 *ptr++ = '*';
374 } else if (*efmp == '>') {
375 fmt_ptr->conthere = true;
376 } else if (efmp == efm + 1) { // analyse prefix
377 if (vim_strchr((char_u *)"+-", *efmp) != NULL) {
378 fmt_ptr->flags = *efmp++;
379 }
380 if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) {
381 fmt_ptr->prefix = *efmp;
382 } else {
383 snprintf((char *)errmsg, CMDBUFFSIZE + 1,
384 _("E376: Invalid %%%c in format string prefix"), *efmp);
385 EMSG(errmsg);
386 return -1;
387 }
388 } else {
389 snprintf((char *)errmsg, CMDBUFFSIZE + 1,
390 _("E377: Invalid %%%c in format string"), *efmp);
391 EMSG(errmsg);
392 return -1;
393 }
394 } else { // copy normal character
395 if (*efmp == '\\' && efmp + 1 < efm + len) {
396 efmp++;
397 } else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL) {
398 *ptr++ = '\\'; // escape regexp atoms
399 }
400 if (*efmp) {
401 *ptr++ = *efmp;
402 }
403 }
404 }
405 *ptr++ = '$';
406 *ptr = NUL;
407
408 return 0;
409}
410
411static efm_T *fmt_start = NULL; // cached across qf_parse_line() calls
412
413static void free_efm_list(efm_T **efm_first)
414{
415 for (efm_T *efm_ptr = *efm_first; efm_ptr != NULL; efm_ptr = *efm_first) {
416 *efm_first = efm_ptr->next;
417 vim_regfree(efm_ptr->prog);
418 xfree(efm_ptr);
419 }
420
421 fmt_start = NULL;
422}
423
424// Parse 'errorformat' option
425static efm_T * parse_efm_option(char_u *efm)
426{
427 efm_T *fmt_ptr = NULL;
428 efm_T *fmt_first = NULL;
429 efm_T *fmt_last = NULL;
430 int len;
431
432 size_t errmsglen = CMDBUFFSIZE + 1;
433 char_u *errmsg = xmalloc(errmsglen);
434
435 // Get some space to modify the format string into.
436 size_t i = (FMT_PATTERNS * 3) + (STRLEN(efm) << 2);
437 for (int round = FMT_PATTERNS - 1; round >= 0; ) {
438 i += STRLEN(fmt_pat[round--].pattern);
439 }
440#ifdef BACKSLASH_IN_FILENAME
441 i += 12; // "%f" can become twelve chars longer (see efm_to_regpat)
442#else
443 i += 2; // "%f" can become two chars longer
444#endif
445 char_u *fmtstr = xmalloc(i);
446
447 while (efm[0] != NUL) {
448 // Allocate a new eformat structure and put it at the end of the list
449 fmt_ptr = (efm_T *)xcalloc(1, sizeof(efm_T));
450 if (fmt_first == NULL) { // first one
451 fmt_first = fmt_ptr;
452 } else {
453 fmt_last->next = fmt_ptr;
454 }
455 fmt_last = fmt_ptr;
456
457 // Isolate one part in the 'errorformat' option
458 for (len = 0; efm[len] != NUL && efm[len] != ','; len++) {
459 if (efm[len] == '\\' && efm[len + 1] != NUL) {
460 len++;
461 }
462 }
463
464 if (efm_to_regpat(efm, len, fmt_ptr, fmtstr, errmsg) == -1) {
465 goto parse_efm_error;
466 }
467 if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL) {
468 goto parse_efm_error;
469 }
470 // Advance to next part
471 efm = skip_to_option_part(efm + len); // skip comma and spaces
472 }
473
474 if (fmt_first == NULL) { // nothing found
475 EMSG(_("E378: 'errorformat' contains no pattern"));
476 }
477
478 goto parse_efm_end;
479
480parse_efm_error:
481 free_efm_list(&fmt_first);
482
483parse_efm_end:
484 xfree(fmtstr);
485 xfree(errmsg);
486
487 return fmt_first;
488}
489
490static char_u *qf_grow_linebuf(qfstate_T *state, size_t newsz)
491{
492 // If the line exceeds LINE_MAXLEN exclude the last
493 // byte since it's not a NL character.
494 state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz;
495 if (state->growbuf == NULL) {
496 state->growbuf = xmalloc(state->linelen + 1);
497 state->growbufsiz = state->linelen;
498 } else if (state->linelen > state->growbufsiz) {
499 state->growbuf = xrealloc(state->growbuf, state->linelen + 1);
500 state->growbufsiz = state->linelen;
501 }
502 return state->growbuf;
503}
504
505/// Get the next string (separated by newline) from state->p_str.
506static int qf_get_next_str_line(qfstate_T *state)
507{
508 // Get the next line from the supplied string
509 char_u *p_str = state->p_str;
510 char_u *p;
511 size_t len;
512
513 if (*p_str == NUL) { // Reached the end of the string
514 return QF_END_OF_INPUT;
515 }
516
517 p = vim_strchr(p_str, '\n');
518 if (p != NULL) {
519 len = (size_t)(p - p_str) + 1;
520 } else {
521 len = STRLEN(p_str);
522 }
523
524 if (len > IOSIZE - 2) {
525 state->linebuf = qf_grow_linebuf(state, len);
526 } else {
527 state->linebuf = IObuff;
528 state->linelen = len;
529 }
530 STRLCPY(state->linebuf, p_str, state->linelen + 1);
531
532 // Increment using len in order to discard the rest of the line if it
533 // exceeds LINE_MAXLEN.
534 p_str += len;
535 state->p_str = p_str;
536
537 return QF_OK;
538}
539
540/// Get the next string from state->p_Li.
541static int qf_get_next_list_line(qfstate_T *state)
542{
543 listitem_T *p_li = state->p_li;
544 size_t len;
545
546 // Get the next line from the supplied list
547 while (p_li != NULL
548 && (TV_LIST_ITEM_TV(p_li)->v_type != VAR_STRING
549 || TV_LIST_ITEM_TV(p_li)->vval.v_string == NULL)) {
550 p_li = TV_LIST_ITEM_NEXT(state->p_list, p_li); // Skip non-string items.
551 }
552
553 if (p_li == NULL) { // End of the list.
554 state->p_li = NULL;
555 return QF_END_OF_INPUT;
556 }
557
558 len = STRLEN(TV_LIST_ITEM_TV(p_li)->vval.v_string);
559 if (len > IOSIZE - 2) {
560 state->linebuf = qf_grow_linebuf(state, len);
561 } else {
562 state->linebuf = IObuff;
563 state->linelen = len;
564 }
565
566 STRLCPY(state->linebuf, TV_LIST_ITEM_TV(p_li)->vval.v_string,
567 state->linelen + 1);
568
569 state->p_li = TV_LIST_ITEM_NEXT(state->p_list, p_li);
570 return QF_OK;
571}
572
573/// Get the next string from state->buf.
574static int qf_get_next_buf_line(qfstate_T *state)
575{
576 char_u *p_buf = NULL;
577 size_t len;
578
579 // Get the next line from the supplied buffer
580 if (state->buflnum > state->lnumlast) {
581 return QF_END_OF_INPUT;
582 }
583 p_buf = ml_get_buf(state->buf, state->buflnum, false);
584 state->buflnum += 1;
585
586 len = STRLEN(p_buf);
587 if (len > IOSIZE - 2) {
588 state->linebuf = qf_grow_linebuf(state, len);
589 } else {
590 state->linebuf = IObuff;
591 state->linelen = len;
592 }
593 STRLCPY(state->linebuf, p_buf, state->linelen + 1);
594
595 return QF_OK;
596}
597
598/// Get the next string from file state->fd.
599static int qf_get_next_file_line(qfstate_T *state)
600{
601 size_t growbuflen;
602
603retry:
604 errno = 0;
605 if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL) {
606 if (errno == EINTR) {
607 goto retry;
608 }
609 return QF_END_OF_INPUT;
610 }
611
612 bool discard = false;
613 state->linelen = STRLEN(IObuff);
614 if (state->linelen == IOSIZE - 1
615 && !(IObuff[state->linelen - 1] == '\n')) {
616 // The current line exceeds IObuff, continue reading using growbuf
617 // until EOL or LINE_MAXLEN bytes is read.
618 if (state->growbuf == NULL) {
619 state->growbufsiz = 2 * (IOSIZE - 1);
620 state->growbuf = xmalloc(state->growbufsiz);
621 }
622
623 // Copy the read part of the line, excluding null-terminator
624 memcpy(state->growbuf, IObuff, IOSIZE - 1);
625 growbuflen = state->linelen;
626
627 for (;;) {
628 errno = 0;
629 if (fgets((char *)state->growbuf + growbuflen,
630 (int)(state->growbufsiz - growbuflen), state->fd) == NULL) {
631 if (errno == EINTR) {
632 continue;
633 }
634 break;
635 }
636 state->linelen = STRLEN(state->growbuf + growbuflen);
637 growbuflen += state->linelen;
638 if (state->growbuf[growbuflen - 1] == '\n') {
639 break;
640 }
641 if (state->growbufsiz == LINE_MAXLEN) {
642 discard = true;
643 break;
644 }
645
646 state->growbufsiz = (2 * state->growbufsiz < LINE_MAXLEN)
647 ? 2 * state->growbufsiz : LINE_MAXLEN;
648 state->growbuf = xrealloc(state->growbuf, state->growbufsiz);
649 }
650
651 while (discard) {
652 // The current line is longer than LINE_MAXLEN, continue reading but
653 // discard everything until EOL or EOF is reached.
654 errno = 0;
655 if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL) {
656 if (errno == EINTR) {
657 continue;
658 }
659 break;
660 }
661 if (STRLEN(IObuff) < IOSIZE - 1 || IObuff[IOSIZE - 1] == '\n') {
662 break;
663 }
664 }
665
666 state->linebuf = state->growbuf;
667 state->linelen = growbuflen;
668 } else {
669 state->linebuf = IObuff;
670 }
671
672 // Convert a line if it contains a non-ASCII character
673 if (state->vc.vc_type != CONV_NONE && has_non_ascii(state->linebuf)) {
674 char_u *line = string_convert(&state->vc, state->linebuf, &state->linelen);
675 if (line != NULL) {
676 if (state->linelen < IOSIZE) {
677 STRLCPY(state->linebuf, line, state->linelen + 1);
678 xfree(line);
679 } else {
680 xfree(state->growbuf);
681 state->linebuf = state->growbuf = line;
682 state->growbufsiz = state->linelen < LINE_MAXLEN
683 ? state->linelen : LINE_MAXLEN;
684 }
685 }
686 }
687 return QF_OK;
688}
689
690/// Get the next string from a file/buffer/list/string.
691static int qf_get_nextline(qfstate_T *state)
692{
693 int status = QF_FAIL;
694
695 if (state->fd == NULL) {
696 if (state->tv != NULL) {
697 if (state->tv->v_type == VAR_STRING) {
698 // Get the next line from the supplied string
699 status = qf_get_next_str_line(state);
700 } else if (state->tv->v_type == VAR_LIST) {
701 // Get the next line from the supplied list
702 status = qf_get_next_list_line(state);
703 }
704 } else {
705 // Get the next line from the supplied buffer
706 status = qf_get_next_buf_line(state);
707 }
708 } else {
709 // Get the next line from the supplied file
710 status = qf_get_next_file_line(state);
711 }
712
713 if (status != QF_OK) {
714 return status;
715 }
716
717 if (state->linelen > 0 && state->linebuf[state->linelen - 1] == '\n') {
718 state->linebuf[state->linelen - 1] = NUL;
719#ifdef USE_CRNL
720 if (state->linelen > 1 && state->linebuf[state->linelen - 2] == '\r') {
721 state->linebuf[state->linelen - 2] = NUL;
722 }
723#endif
724 }
725
726 remove_bom(state->linebuf);
727
728 return QF_OK;
729}
730
731// Returns true if the specified quickfix/location list is empty.
732static bool qf_list_empty(const qf_info_T *qi, int qf_idx)
733 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
734{
735 if (qi == NULL || qf_idx < 0 || qf_idx >= LISTCOUNT) {
736 return true;
737 }
738 return qi->qf_lists[qf_idx].qf_count <= 0;
739}
740
741/// Parse a line and get the quickfix fields.
742/// Return the QF_ status.
743static int qf_parse_line(qf_info_T *qi, int qf_idx, char_u *linebuf,
744 size_t linelen, efm_T *fmt_first, qffields_T *fields)
745{
746 efm_T *fmt_ptr;
747 int idx = 0;
748 char_u *tail = NULL;
749 qf_list_T *qfl = &qi->qf_lists[qf_idx];
750 int status;
751
752restofline:
753 // If there was no %> item start at the first pattern
754 if (fmt_start == NULL) {
755 fmt_ptr = fmt_first;
756 } else {
757 // Otherwise start from the last used pattern.
758 fmt_ptr = fmt_start;
759 fmt_start = NULL;
760 }
761
762 // Try to match each part of 'errorformat' until we find a complete
763 // match or no match.
764 fields->valid = true;
765 for (; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) {
766 idx = fmt_ptr->prefix;
767 status = qf_parse_get_fields(linebuf, linelen, fmt_ptr, fields,
768 qfl->qf_multiline, qfl->qf_multiscan,
769 &tail);
770 if (status == QF_NOMEM) {
771 return status;
772 }
773 if (status == QF_OK) {
774 break;
775 }
776 }
777 qfl->qf_multiscan = false;
778
779 if (fmt_ptr == NULL || idx == 'D' || idx == 'X') {
780 if (fmt_ptr != NULL) {
781 // 'D' and 'X' directory specifiers.
782 status = qf_parse_dir_pfx(idx, fields, qfl);
783 if (status != QF_OK) {
784 return status;
785 }
786 }
787 status = qf_parse_line_nomatch(linebuf, linelen, fields);
788 if (status != QF_OK) {
789 return status;
790 }
791 if (fmt_ptr == NULL) {
792 qfl->qf_multiline = qfl->qf_multiignore = false;
793 }
794 } else {
795 // honor %> item
796 if (fmt_ptr->conthere) {
797 fmt_start = fmt_ptr;
798 }
799
800 if (vim_strchr((char_u *)"AEWI", idx) != NULL) {
801 qfl->qf_multiline = true; // start of a multi-line message
802 qfl->qf_multiignore = false; // reset continuation
803 } else if (vim_strchr((char_u *)"CZ", idx) != NULL) {
804 // continuation of multi-line msg
805 status = qf_parse_multiline_pfx(qi, qf_idx, idx, qfl, fields);
806 if (status != QF_OK) {
807 return status;
808 }
809 } else if (vim_strchr((char_u *)"OPQ", idx) != NULL) {
810 // global file names
811 status = qf_parse_file_pfx(idx, fields, qfl, tail);
812 if (status == QF_MULTISCAN) {
813 goto restofline;
814 }
815 }
816 if (fmt_ptr->flags == '-') { // generally exclude this line
817 if (qfl->qf_multiline) {
818 // also exclude continuation lines
819 qfl->qf_multiignore = true;
820 }
821 return QF_IGNORE_LINE;
822 }
823 }
824
825 return QF_OK;
826}
827
828// Read the errorfile "efile" into memory, line by line, building the error
829// list.
830// Alternative: when "efile" is NULL read errors from buffer "buf".
831// Alternative: when "tv" is not NULL get errors from the string or list.
832// Always use 'errorformat' from "buf" if there is a local value.
833// Then "lnumfirst" and "lnumlast" specify the range of lines to use.
834// Set the title of the list to "qf_title".
835// Return -1 for error, number of errors for success.
836static int
837qf_init_ext(
838 qf_info_T *qi,
839 int qf_idx,
840 char_u *efile,
841 buf_T *buf,
842 typval_T *tv,
843 char_u *errorformat,
844 int newlist, // TRUE: start a new error list
845 linenr_T lnumfirst, // first line number to use
846 linenr_T lnumlast, // last line number to use
847 char_u *qf_title,
848 char_u *enc
849)
850{
851 qfstate_T state;
852 qffields_T fields;
853 qfline_T *old_last = NULL;
854 bool adding = false;
855 static efm_T *fmt_first = NULL;
856 char_u *efm;
857 static char_u *last_efm = NULL;
858 int retval = -1; // default: return error flag
859 int status;
860
861 // Do not used the cached buffer, it may have been wiped out.
862 XFREE_CLEAR(qf_last_bufname);
863
864 memset(&state, 0, sizeof(state));
865 memset(&fields, 0, sizeof(fields));
866 state.vc.vc_type = CONV_NONE;
867 if (enc != NULL && *enc != NUL) {
868 convert_setup(&state.vc, enc, p_enc);
869 }
870
871 fields.namebuf = xmalloc(CMDBUFFSIZE + 1);
872 fields.module = xmalloc(CMDBUFFSIZE + 1);
873 fields.errmsglen = CMDBUFFSIZE + 1;
874 fields.errmsg = xmalloc(fields.errmsglen);
875 fields.pattern = xmalloc(CMDBUFFSIZE + 1);
876
877 if (efile != NULL && (state.fd = os_fopen((char *)efile, "r")) == NULL) {
878 EMSG2(_(e_openerrf), efile);
879 goto qf_init_end;
880 }
881
882 if (newlist || qf_idx == qi->qf_listcount) {
883 // make place for a new list
884 qf_new_list(qi, qf_title);
885 qf_idx = qi->qf_curlist;
886 } else {
887 // Adding to existing list, use last entry.
888 adding = true;
889 if (qi->qf_lists[qf_idx].qf_count > 0) {
890 old_last = qi->qf_lists[qf_idx].qf_last;
891 }
892 }
893
894 qf_list_T *qfl = &qi->qf_lists[qf_idx];
895
896 // Use the local value of 'errorformat' if it's set.
897 if (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) {
898 efm = buf->b_p_efm;
899 } else {
900 efm = errorformat;
901 }
902
903 // If the errorformat didn't change between calls, then reuse the previously
904 // parsed values.
905 if (last_efm == NULL || (STRCMP(last_efm, efm) != 0)) {
906 // free the previously parsed data
907 XFREE_CLEAR(last_efm);
908 free_efm_list(&fmt_first);
909
910 // parse the current 'efm'
911 fmt_first = parse_efm_option(efm);
912 if (fmt_first != NULL) {
913 last_efm = vim_strsave(efm);
914 }
915 }
916
917 if (fmt_first == NULL) { // nothing found
918 goto error2;
919 }
920
921 /*
922 * got_int is reset here, because it was probably set when killing the
923 * ":make" command, but we still want to read the errorfile then.
924 */
925 got_int = FALSE;
926
927 if (tv != NULL) {
928 if (tv->v_type == VAR_STRING) {
929 state.p_str = tv->vval.v_string;
930 } else if (tv->v_type == VAR_LIST) {
931 state.p_list = tv->vval.v_list;
932 state.p_li = tv_list_first(tv->vval.v_list);
933 }
934 state.tv = tv;
935 }
936 state.buf = buf;
937 state.buflnum = lnumfirst;
938 state.lnumlast = lnumlast;
939
940 /*
941 * Read the lines in the error file one by one.
942 * Try to recognize one of the error formats in each line.
943 */
944 while (!got_int) {
945 // Get the next line from a file/buffer/list/string
946 status = qf_get_nextline(&state);
947 if (status == QF_END_OF_INPUT) { // end of input
948 break;
949 }
950
951 status = qf_parse_line(qi, qf_idx, state.linebuf, state.linelen,
952 fmt_first, &fields);
953 if (status == QF_FAIL) {
954 goto error2;
955 }
956 if (status == QF_IGNORE_LINE) {
957 continue;
958 }
959
960 if (qf_add_entry(qi,
961 qf_idx,
962 qfl->qf_directory,
963 (*fields.namebuf || qfl->qf_directory)
964 ? fields.namebuf : ((qfl->qf_currfile && fields.valid)
965 ? qfl->qf_currfile : (char_u *)NULL),
966 fields.module,
967 0,
968 fields.errmsg,
969 fields.lnum,
970 fields.col,
971 fields.use_viscol,
972 fields.pattern,
973 fields.enr,
974 fields.type,
975 fields.valid) == FAIL) {
976 goto error2;
977 }
978 line_breakcheck();
979 }
980 if (state.fd == NULL || !ferror(state.fd)) {
981 if (qfl->qf_index == 0) {
982 // no valid entry found
983 qfl->qf_ptr = qfl->qf_start;
984 qfl->qf_index = 1;
985 qfl->qf_nonevalid = true;
986 } else {
987 qfl->qf_nonevalid = false;
988 if (qfl->qf_ptr == NULL) {
989 qfl->qf_ptr = qfl->qf_start;
990 }
991 }
992 // return number of matches
993 retval = qfl->qf_count;
994 goto qf_init_end;
995 }
996 EMSG(_(e_readerrf));
997error2:
998 if (!adding) {
999 // Error when creating a new list. Free the new list
1000 qf_free(qi, qi->qf_curlist);
1001 qi->qf_listcount--;
1002 if (qi->qf_curlist > 0) {
1003 qi->qf_curlist--;
1004 }
1005 }
1006qf_init_end:
1007 if (state.fd != NULL) {
1008 fclose(state.fd);
1009 }
1010 xfree(fields.namebuf);
1011 xfree(fields.module);
1012 xfree(fields.errmsg);
1013 xfree(fields.pattern);
1014 xfree(state.growbuf);
1015
1016 if (qf_idx == qi->qf_curlist) {
1017 qf_update_buffer(qi, old_last);
1018 }
1019
1020 if (state.vc.vc_type != CONV_NONE) {
1021 convert_setup(&state.vc, NULL, NULL);
1022 }
1023
1024 return retval;
1025}
1026
1027/// Set the title of the specified quickfix list. Frees the previous title.
1028/// Prepends ':' to the title.
1029static void qf_store_title(qf_info_T *qi, int qf_idx, const char_u *title)
1030 FUNC_ATTR_NONNULL_ARG(1)
1031{
1032 XFREE_CLEAR(qi->qf_lists[qf_idx].qf_title);
1033
1034 if (title != NULL) {
1035 size_t len = STRLEN(title) + 1;
1036 char_u *p = xmallocz(len);
1037
1038 qi->qf_lists[qf_idx].qf_title = p;
1039 xstrlcpy((char *)p, (const char *)title, len + 1);
1040 }
1041}
1042
1043/// The title of a quickfix/location list is set, by default, to the command
1044/// that created the quickfix list with the ":" prefix.
1045/// Create a quickfix list title string by prepending ":" to a user command.
1046/// Returns a pointer to a static buffer with the title.
1047static char_u * qf_cmdtitle(char_u *cmd)
1048{
1049 static char_u qftitle_str[IOSIZE];
1050
1051 snprintf((char *)qftitle_str, IOSIZE, ":%s", (char *)cmd);
1052
1053 return qftitle_str;
1054}
1055
1056// Prepare for adding a new quickfix list. If the current list is in the
1057// middle of the stack, then all the following lists are freed and then
1058// the new list is added.
1059static void qf_new_list(qf_info_T *qi, char_u *qf_title)
1060{
1061 int i;
1062
1063 // If the current entry is not the last entry, delete entries beyond
1064 // the current entry. This makes it possible to browse in a tree-like
1065 // way with ":grep'.
1066 while (qi->qf_listcount > qi->qf_curlist + 1)
1067 qf_free(qi, --qi->qf_listcount);
1068
1069 /*
1070 * When the stack is full, remove to oldest entry
1071 * Otherwise, add a new entry.
1072 */
1073 if (qi->qf_listcount == LISTCOUNT) {
1074 qf_free(qi, 0);
1075 for (i = 1; i < LISTCOUNT; ++i)
1076 qi->qf_lists[i - 1] = qi->qf_lists[i];
1077 qi->qf_curlist = LISTCOUNT - 1;
1078 } else
1079 qi->qf_curlist = qi->qf_listcount++;
1080 memset(&qi->qf_lists[qi->qf_curlist], 0, (size_t)(sizeof(qf_list_T)));
1081 qf_store_title(qi, qi->qf_curlist, qf_title);
1082 qi->qf_lists[qi->qf_curlist].qf_id = ++last_qf_id;
1083}
1084
1085/// Parse the error format matches in 'regmatch' and set the values in 'fields'.
1086/// fmt_ptr contains the 'efm' format specifiers/prefixes that have a match.
1087/// Returns QF_OK if all the matches are successfully parsed. On failure,
1088/// returns QF_FAIL or QF_NOMEM.
1089static int qf_parse_match(char_u *linebuf, size_t linelen, efm_T *fmt_ptr,
1090 regmatch_T *regmatch, qffields_T *fields,
1091 int qf_multiline, int qf_multiscan, char_u **tail)
1092{
1093 char_u idx = fmt_ptr->prefix;
1094 int i;
1095 size_t len;
1096
1097 if ((idx == 'C' || idx == 'Z') && !qf_multiline) {
1098 return QF_FAIL;
1099 }
1100 if (vim_strchr((char_u *)"EWI", idx) != NULL) {
1101 fields->type = idx;
1102 } else {
1103 fields->type = 0;
1104 }
1105
1106 // Extract error message data from matched line.
1107 // We check for an actual submatch, because "\[" and "\]" in
1108 // the 'errorformat' may cause the wrong submatch to be used.
1109 if ((i = (int)fmt_ptr->addr[0]) > 0) { // %f
1110 if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL) {
1111 return QF_FAIL;
1112 }
1113
1114 // Expand ~/file and $HOME/file to full path.
1115 char_u c = *regmatch->endp[i];
1116 *regmatch->endp[i] = NUL;
1117 expand_env(regmatch->startp[i], fields->namebuf, CMDBUFFSIZE);
1118 *regmatch->endp[i] = c;
1119
1120 if (vim_strchr((char_u *)"OPQ", idx) != NULL
1121 && !os_path_exists(fields->namebuf)) {
1122 return QF_FAIL;
1123 }
1124 }
1125 if ((i = (int)fmt_ptr->addr[1]) > 0) { // %n
1126 if (regmatch->startp[i] == NULL) {
1127 return QF_FAIL;
1128 }
1129 fields->enr = (int)atol((char *)regmatch->startp[i]);
1130 }
1131 if ((i = (int)fmt_ptr->addr[2]) > 0) { // %l
1132 if (regmatch->startp[i] == NULL) {
1133 return QF_FAIL;
1134 }
1135 fields->lnum = atol((char *)regmatch->startp[i]);
1136 }
1137 if ((i = (int)fmt_ptr->addr[3]) > 0) { // %c
1138 if (regmatch->startp[i] == NULL) {
1139 return QF_FAIL;
1140 }
1141 fields->col = (int)atol((char *)regmatch->startp[i]);
1142 }
1143 if ((i = (int)fmt_ptr->addr[4]) > 0) { // %t
1144 if (regmatch->startp[i] == NULL) {
1145 return QF_FAIL;
1146 }
1147 fields->type = *regmatch->startp[i];
1148 }
1149 if (fmt_ptr->flags == '+' && !qf_multiscan) { // %+
1150 if (linelen >= fields->errmsglen) {
1151 // linelen + null terminator
1152 fields->errmsg = xrealloc(fields->errmsg, linelen + 1);
1153 fields->errmsglen = linelen + 1;
1154 }
1155 STRLCPY(fields->errmsg, linebuf, linelen + 1);
1156 } else if ((i = (int)fmt_ptr->addr[5]) > 0) { // %m
1157 if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL) {
1158 return QF_FAIL;
1159 }
1160 len = (size_t)(regmatch->endp[i] - regmatch->startp[i]);
1161 if (len >= fields->errmsglen) {
1162 // len + null terminator
1163 fields->errmsg = xrealloc(fields->errmsg, len + 1);
1164 fields->errmsglen = len + 1;
1165 }
1166 STRLCPY(fields->errmsg, regmatch->startp[i], len + 1);
1167 }
1168 if ((i = (int)fmt_ptr->addr[6]) > 0) { // %r
1169 if (regmatch->startp[i] == NULL) {
1170 return QF_FAIL;
1171 }
1172 *tail = regmatch->startp[i];
1173 }
1174 if ((i = (int)fmt_ptr->addr[7]) > 0) { // %p
1175 if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL) {
1176 return QF_FAIL;
1177 }
1178 fields->col = 0;
1179 char_u *match_ptr;
1180 for (match_ptr = regmatch->startp[i]; match_ptr != regmatch->endp[i];
1181 match_ptr++) {
1182 fields->col++;
1183 if (*match_ptr == TAB) {
1184 fields->col += 7;
1185 fields->col -= fields->col % 8;
1186 }
1187 }
1188 fields->col++;
1189 fields->use_viscol = true;
1190 }
1191 if ((i = (int)fmt_ptr->addr[8]) > 0) { // %v
1192 if (regmatch->startp[i] == NULL) {
1193 return QF_FAIL;
1194 }
1195 fields->col = (int)atol((char *)regmatch->startp[i]);
1196 fields->use_viscol = true;
1197 }
1198 if ((i = (int)fmt_ptr->addr[9]) > 0) { // %s
1199 if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL) {
1200 return QF_FAIL;
1201 }
1202 len = (size_t)(regmatch->endp[i] - regmatch->startp[i]);
1203 if (len > CMDBUFFSIZE - 5) {
1204 len = CMDBUFFSIZE - 5;
1205 }
1206 STRCPY(fields->pattern, "^\\V");
1207 STRNCAT(fields->pattern, regmatch->startp[i], len);
1208 fields->pattern[len + 3] = '\\';
1209 fields->pattern[len + 4] = '$';
1210 fields->pattern[len + 5] = NUL;
1211 }
1212 if ((i = (int)fmt_ptr->addr[10]) > 0) { // %o
1213 if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL) {
1214 return QF_FAIL;
1215 }
1216 len = (size_t)(regmatch->endp[i] - regmatch->startp[i]);
1217 if (len > CMDBUFFSIZE) {
1218 len = CMDBUFFSIZE;
1219 }
1220 STRNCAT(fields->module, regmatch->startp[i], len);
1221 }
1222
1223 return QF_OK;
1224}
1225
1226/// Parse an error line in 'linebuf' using a single error format string in
1227/// 'fmt_ptr->prog' and return the matching values in 'fields'.
1228/// Returns QF_OK if the efm format matches completely and the fields are
1229/// successfully copied. Otherwise returns QF_FAIL or QF_NOMEM.
1230static int qf_parse_get_fields(char_u *linebuf, size_t linelen, efm_T *fmt_ptr,
1231 qffields_T *fields, int qf_multiline,
1232 int qf_multiscan, char_u **tail)
1233{
1234 regmatch_T regmatch;
1235 int status = QF_FAIL;
1236 int r;
1237
1238 if (qf_multiscan && vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL) {
1239 return QF_FAIL;
1240 }
1241
1242 fields->namebuf[0] = NUL;
1243 fields->module[0] = NUL;
1244 fields->pattern[0] = NUL;
1245 if (!qf_multiscan) {
1246 fields->errmsg[0] = NUL;
1247 }
1248 fields->lnum = 0;
1249 fields->col = 0;
1250 fields->use_viscol = false;
1251 fields->enr = -1;
1252 fields->type = 0;
1253 *tail = NULL;
1254
1255 // Always ignore case when looking for a matching error.
1256 regmatch.rm_ic = true;
1257 regmatch.regprog = fmt_ptr->prog;
1258 r = vim_regexec(&regmatch, linebuf, (colnr_T)0);
1259 fmt_ptr->prog = regmatch.regprog;
1260 if (r) {
1261 status = qf_parse_match(linebuf, linelen, fmt_ptr, &regmatch, fields,
1262 qf_multiline, qf_multiscan, tail);
1263 }
1264
1265 return status;
1266}
1267
1268/// Parse directory error format prefixes (%D and %X).
1269/// Push and pop directories from the directory stack when scanning directory
1270/// names.
1271static int qf_parse_dir_pfx(int idx, qffields_T *fields, qf_list_T *qfl)
1272{
1273 if (idx == 'D') { // enter directory
1274 if (*fields->namebuf == NUL) {
1275 EMSG(_("E379: Missing or empty directory name"));
1276 return QF_FAIL;
1277 }
1278 qfl->qf_directory = qf_push_dir(fields->namebuf, &qfl->qf_dir_stack, false);
1279 if (qfl->qf_directory == NULL) {
1280 return QF_FAIL;
1281 }
1282 } else if (idx == 'X') { // leave directory
1283 qfl->qf_directory = qf_pop_dir(&qfl->qf_dir_stack);
1284 }
1285
1286 return QF_OK;
1287}
1288
1289/// Parse global file name error format prefixes (%O, %P and %Q).
1290static int qf_parse_file_pfx(int idx, qffields_T *fields, qf_list_T *qfl,
1291 char_u *tail)
1292{
1293 fields->valid = false;
1294 if (*fields->namebuf == NUL || os_path_exists(fields->namebuf)) {
1295 if (*fields->namebuf && idx == 'P') {
1296 qfl->qf_currfile = qf_push_dir(fields->namebuf, &qfl->qf_file_stack,
1297 true);
1298 } else if (idx == 'Q') {
1299 qfl->qf_currfile = qf_pop_dir(&qfl->qf_file_stack);
1300 }
1301 *fields->namebuf = NUL;
1302 if (tail && *tail) {
1303 STRMOVE(IObuff, skipwhite(tail));
1304 qfl->qf_multiscan = true;
1305 return QF_MULTISCAN;
1306 }
1307 }
1308
1309 return QF_OK;
1310}
1311
1312/// Parse a non-error line (a line which doesn't match any of the error
1313/// format in 'efm').
1314static int qf_parse_line_nomatch(char_u *linebuf, size_t linelen,
1315 qffields_T *fields)
1316{
1317 fields->namebuf[0] = NUL; // no match found, remove file name
1318 fields->lnum = 0; // don't jump to this line
1319 fields->valid = false;
1320 if (linelen >= fields->errmsglen) {
1321 // linelen + null terminator
1322 fields->errmsg = xrealloc(fields->errmsg, linelen + 1);
1323 fields->errmsglen = linelen + 1;
1324 }
1325 // copy whole line to error message
1326 STRLCPY(fields->errmsg, linebuf, linelen + 1);
1327
1328 return QF_OK;
1329}
1330
1331/// Parse multi-line error format prefixes (%C and %Z)
1332static int qf_parse_multiline_pfx(qf_info_T *qi, int qf_idx, int idx,
1333 qf_list_T *qfl, qffields_T *fields)
1334{
1335 if (!qfl->qf_multiignore) {
1336 qfline_T *qfprev = qfl->qf_last;
1337
1338 if (qfprev == NULL) {
1339 return QF_FAIL;
1340 }
1341 if (*fields->errmsg) {
1342 size_t textlen = strlen((char *)qfprev->qf_text);
1343 size_t errlen = strlen((char *)fields->errmsg);
1344 qfprev->qf_text = xrealloc(qfprev->qf_text, textlen + errlen + 2);
1345 qfprev->qf_text[textlen] = '\n';
1346 STRCPY(qfprev->qf_text + textlen + 1, fields->errmsg);
1347 }
1348 if (qfprev->qf_nr == -1) {
1349 qfprev->qf_nr = fields->enr;
1350 }
1351 if (vim_isprintc(fields->type) && !qfprev->qf_type) {
1352 // only printable chars allowed
1353 qfprev->qf_type = fields->type;
1354 }
1355
1356 if (!qfprev->qf_lnum) {
1357 qfprev->qf_lnum = fields->lnum;
1358 }
1359 if (!qfprev->qf_col) {
1360 qfprev->qf_col = fields->col;
1361 }
1362 qfprev->qf_viscol = fields->use_viscol;
1363 if (!qfprev->qf_fnum) {
1364 qfprev->qf_fnum = qf_get_fnum(qi, qf_idx, qfl->qf_directory,
1365 *fields->namebuf || qfl->qf_directory
1366 ? fields->namebuf
1367 : qfl->qf_currfile && fields->valid
1368 ? qfl->qf_currfile : 0);
1369 }
1370 }
1371 if (idx == 'Z') {
1372 qfl->qf_multiline = qfl->qf_multiignore = false;
1373 }
1374 line_breakcheck();
1375
1376 return QF_IGNORE_LINE;
1377}
1378
1379/// Free a location list.
1380static void ll_free_all(qf_info_T **pqi)
1381{
1382 int i;
1383 qf_info_T *qi;
1384
1385 qi = *pqi;
1386 if (qi == NULL)
1387 return;
1388 *pqi = NULL; /* Remove reference to this list */
1389
1390 qi->qf_refcount--;
1391 if (qi->qf_refcount < 1) {
1392 /* No references to this location list */
1393 for (i = 0; i < qi->qf_listcount; ++i)
1394 qf_free(qi, i);
1395 xfree(qi);
1396 }
1397}
1398
1399/// Free all the quickfix/location lists in the stack.
1400void qf_free_all(win_T *wp)
1401{
1402 int i;
1403 qf_info_T *qi = &ql_info;
1404
1405 if (wp != NULL) {
1406 /* location list */
1407 ll_free_all(&wp->w_llist);
1408 ll_free_all(&wp->w_llist_ref);
1409 } else
1410 /* quickfix list */
1411 for (i = 0; i < qi->qf_listcount; ++i)
1412 qf_free(qi, i);
1413}
1414
1415/// Add an entry to the end of the list of errors.
1416///
1417/// @param qi quickfix list
1418/// @param qf_idx list index
1419/// @param dir optional directory name
1420/// @param fname file name or NULL
1421/// @param module module name or NULL
1422/// @param bufnum buffer number or zero
1423/// @param mesg message
1424/// @param lnum line number
1425/// @param col column
1426/// @param vis_col using visual column
1427/// @param pattern search pattern
1428/// @param nr error number
1429/// @param type type character
1430/// @param valid valid entry
1431///
1432/// @returns OK or FAIL.
1433static int qf_add_entry(qf_info_T *qi, int qf_idx, char_u *dir, char_u *fname,
1434 char_u *module, int bufnum, char_u *mesg, long lnum,
1435 int col, char_u vis_col, char_u *pattern, int nr,
1436 char_u type, char_u valid)
1437{
1438 qfline_T *qfp = xmalloc(sizeof(qfline_T));
1439 qfline_T **lastp; // pointer to qf_last or NULL
1440
1441 if (bufnum != 0) {
1442 buf_T *buf = buflist_findnr(bufnum);
1443
1444 qfp->qf_fnum = bufnum;
1445 if (buf != NULL) {
1446 buf->b_has_qf_entry |=
1447 IS_QF_STACK(qi) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
1448 }
1449 } else {
1450 qfp->qf_fnum = qf_get_fnum(qi, qf_idx, dir, fname);
1451 }
1452 qfp->qf_text = vim_strsave(mesg);
1453 qfp->qf_lnum = lnum;
1454 qfp->qf_col = col;
1455 qfp->qf_viscol = vis_col;
1456 if (pattern == NULL || *pattern == NUL) {
1457 qfp->qf_pattern = NULL;
1458 } else {
1459 qfp->qf_pattern = vim_strsave(pattern);
1460 }
1461 if (module == NULL || *module == NUL) {
1462 qfp->qf_module = NULL;
1463 } else {
1464 qfp->qf_module = vim_strsave(module);
1465 }
1466 qfp->qf_nr = nr;
1467 if (type != 1 && !vim_isprintc(type)) { // only printable chars allowed
1468 type = 0;
1469 }
1470 qfp->qf_type = (char_u)type;
1471 qfp->qf_valid = valid;
1472
1473 lastp = &qi->qf_lists[qf_idx].qf_last;
1474 if (qi->qf_lists[qf_idx].qf_count == 0) {
1475 // first element in the list
1476 qi->qf_lists[qf_idx].qf_start = qfp;
1477 qi->qf_lists[qf_idx].qf_ptr = qfp;
1478 qi->qf_lists[qf_idx].qf_index = 0;
1479 qfp->qf_prev = NULL;
1480 } else {
1481 assert(*lastp);
1482 qfp->qf_prev = *lastp;
1483 (*lastp)->qf_next = qfp;
1484 }
1485 qfp->qf_next = NULL;
1486 qfp->qf_cleared = false;
1487 *lastp = qfp;
1488 qi->qf_lists[qf_idx].qf_count++;
1489 if (qi->qf_lists[qf_idx].qf_index == 0 && qfp->qf_valid) {
1490 // first valid entry
1491 qi->qf_lists[qf_idx].qf_index = qi->qf_lists[qf_idx].qf_count;
1492 qi->qf_lists[qf_idx].qf_ptr = qfp;
1493 }
1494
1495 return OK;
1496}
1497
1498/*
1499 * Allocate a new location list
1500 */
1501static qf_info_T *ll_new_list(void)
1502{
1503 qf_info_T *qi = xcalloc(1, sizeof(qf_info_T));
1504 qi->qf_refcount++;
1505
1506 return qi;
1507}
1508
1509/*
1510 * Return the location list for window 'wp'.
1511 * If not present, allocate a location list
1512 */
1513static qf_info_T *ll_get_or_alloc_list(win_T *wp)
1514{
1515 if (IS_LL_WINDOW(wp))
1516 /* For a location list window, use the referenced location list */
1517 return wp->w_llist_ref;
1518
1519 /*
1520 * For a non-location list window, w_llist_ref should not point to a
1521 * location list.
1522 */
1523 ll_free_all(&wp->w_llist_ref);
1524
1525 if (wp->w_llist == NULL)
1526 wp->w_llist = ll_new_list(); /* new location list */
1527 return wp->w_llist;
1528}
1529
1530/*
1531 * Copy the location list from window "from" to window "to".
1532 */
1533void copy_loclist(win_T *from, win_T *to)
1534{
1535 qf_info_T *qi;
1536 int idx;
1537 int i;
1538
1539 /*
1540 * When copying from a location list window, copy the referenced
1541 * location list. For other windows, copy the location list for
1542 * that window.
1543 */
1544 if (IS_LL_WINDOW(from))
1545 qi = from->w_llist_ref;
1546 else
1547 qi = from->w_llist;
1548
1549 if (qi == NULL) /* no location list to copy */
1550 return;
1551
1552 /* allocate a new location list */
1553 to->w_llist = ll_new_list();
1554
1555 to->w_llist->qf_listcount = qi->qf_listcount;
1556
1557 /* Copy the location lists one at a time */
1558 for (idx = 0; idx < qi->qf_listcount; idx++) {
1559 qf_list_T *from_qfl;
1560 qf_list_T *to_qfl;
1561
1562 to->w_llist->qf_curlist = idx;
1563
1564 from_qfl = &qi->qf_lists[idx];
1565 to_qfl = &to->w_llist->qf_lists[idx];
1566
1567 /* Some of the fields are populated by qf_add_entry() */
1568 to_qfl->qf_nonevalid = from_qfl->qf_nonevalid;
1569 to_qfl->qf_count = 0;
1570 to_qfl->qf_index = 0;
1571 to_qfl->qf_start = NULL;
1572 to_qfl->qf_last = NULL;
1573 to_qfl->qf_ptr = NULL;
1574 if (from_qfl->qf_title != NULL)
1575 to_qfl->qf_title = vim_strsave(from_qfl->qf_title);
1576 else
1577 to_qfl->qf_title = NULL;
1578
1579 if (from_qfl->qf_ctx != NULL) {
1580 to_qfl->qf_ctx = xcalloc(1, sizeof(typval_T));
1581 tv_copy(from_qfl->qf_ctx, to_qfl->qf_ctx);
1582 } else {
1583 to_qfl->qf_ctx = NULL;
1584 }
1585
1586 if (from_qfl->qf_count) {
1587 qfline_T *from_qfp;
1588 qfline_T *prevp;
1589
1590 // copy all the location entries in this list
1591 for (i = 0, from_qfp = from_qfl->qf_start;
1592 i < from_qfl->qf_count && from_qfp != NULL;
1593 i++, from_qfp = from_qfp->qf_next) {
1594 if (qf_add_entry(to->w_llist,
1595 to->w_llist->qf_curlist,
1596 NULL,
1597 NULL,
1598 from_qfp->qf_module,
1599 0,
1600 from_qfp->qf_text,
1601 from_qfp->qf_lnum,
1602 from_qfp->qf_col,
1603 from_qfp->qf_viscol,
1604 from_qfp->qf_pattern,
1605 from_qfp->qf_nr,
1606 0,
1607 from_qfp->qf_valid) == FAIL) {
1608 qf_free_all(to);
1609 return;
1610 }
1611 /*
1612 * qf_add_entry() will not set the qf_num field, as the
1613 * directory and file names are not supplied. So the qf_fnum
1614 * field is copied here.
1615 */
1616 prevp = to->w_llist->qf_lists[to->w_llist->qf_curlist].qf_last;
1617 prevp->qf_fnum = from_qfp->qf_fnum; // file number
1618 prevp->qf_type = from_qfp->qf_type; // error type
1619 if (from_qfl->qf_ptr == from_qfp) {
1620 to_qfl->qf_ptr = prevp; // current location
1621 }
1622 }
1623 }
1624
1625 to_qfl->qf_index = from_qfl->qf_index; /* current index in the list */
1626
1627 // Assign a new ID for the location list
1628 to_qfl->qf_id = ++last_qf_id;
1629 to_qfl->qf_changedtick = 0L;
1630
1631 /* When no valid entries are present in the list, qf_ptr points to
1632 * the first item in the list */
1633 if (to_qfl->qf_nonevalid) {
1634 to_qfl->qf_ptr = to_qfl->qf_start;
1635 to_qfl->qf_index = 1;
1636 }
1637 }
1638
1639 to->w_llist->qf_curlist = qi->qf_curlist; /* current list */
1640}
1641
1642// Get buffer number for file "directory/fname".
1643// Also sets the b_has_qf_entry flag.
1644static int qf_get_fnum(qf_info_T *qi, int qf_idx, char_u *directory,
1645 char_u *fname)
1646{
1647 char_u *ptr = NULL;
1648 char_u *bufname;
1649 buf_T *buf;
1650 if (fname == NULL || *fname == NUL) { // no file name
1651 return 0;
1652 }
1653
1654#ifdef BACKSLASH_IN_FILENAME
1655 if (directory != NULL) {
1656 slash_adjust(directory);
1657 }
1658 slash_adjust(fname);
1659#endif
1660 if (directory != NULL && !vim_isAbsName(fname)) {
1661 ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, true);
1662 // Here we check if the file really exists.
1663 // This should normally be true, but if make works without
1664 // "leaving directory"-messages we might have missed a
1665 // directory change.
1666 if (!os_path_exists(ptr)) {
1667 xfree(ptr);
1668 directory = qf_guess_filepath(qi, qf_idx, fname);
1669 if (directory) {
1670 ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, true);
1671 } else {
1672 ptr = vim_strsave(fname);
1673 }
1674 }
1675 // Use concatenated directory name and file name.
1676 bufname = ptr;
1677 } else {
1678 bufname = fname;
1679 }
1680
1681 if (qf_last_bufname != NULL
1682 && STRCMP(bufname, qf_last_bufname) == 0
1683 && bufref_valid(&qf_last_bufref)) {
1684 buf = qf_last_bufref.br_buf;
1685 xfree(ptr);
1686 } else {
1687 xfree(qf_last_bufname);
1688 buf = buflist_new(bufname, NULL, (linenr_T)0, BLN_NOOPT);
1689 qf_last_bufname = (bufname == ptr) ? bufname : vim_strsave(bufname);
1690 set_bufref(&qf_last_bufref, buf);
1691 }
1692 if (buf == NULL) {
1693 return 0;
1694 }
1695 buf->b_has_qf_entry =
1696 IS_QF_STACK(qi) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
1697 return buf->b_fnum;
1698}
1699
1700// Push dirbuf onto the directory stack and return pointer to actual dir or
1701// NULL on error.
1702static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr,
1703 bool is_file_stack)
1704{
1705 struct dir_stack_T *ds_ptr;
1706
1707 /* allocate new stack element and hook it in */
1708 struct dir_stack_T *ds_new = xmalloc(sizeof(struct dir_stack_T));
1709
1710 ds_new->next = *stackptr;
1711 *stackptr = ds_new;
1712
1713 /* store directory on the stack */
1714 if (vim_isAbsName(dirbuf)
1715 || (*stackptr)->next == NULL
1716 || (*stackptr && is_file_stack))
1717 (*stackptr)->dirname = vim_strsave(dirbuf);
1718 else {
1719 /* Okay we don't have an absolute path.
1720 * dirbuf must be a subdir of one of the directories on the stack.
1721 * Let's search...
1722 */
1723 ds_new = (*stackptr)->next;
1724 (*stackptr)->dirname = NULL;
1725 while (ds_new) {
1726 xfree((*stackptr)->dirname);
1727 (*stackptr)->dirname = (char_u *)concat_fnames((char *)ds_new->dirname,
1728 (char *)dirbuf, TRUE);
1729 if (os_isdir((*stackptr)->dirname))
1730 break;
1731
1732 ds_new = ds_new->next;
1733 }
1734
1735 /* clean up all dirs we already left */
1736 while ((*stackptr)->next != ds_new) {
1737 ds_ptr = (*stackptr)->next;
1738 (*stackptr)->next = (*stackptr)->next->next;
1739 xfree(ds_ptr->dirname);
1740 xfree(ds_ptr);
1741 }
1742
1743 /* Nothing found -> it must be on top level */
1744 if (ds_new == NULL) {
1745 xfree((*stackptr)->dirname);
1746 (*stackptr)->dirname = vim_strsave(dirbuf);
1747 }
1748 }
1749
1750 if ((*stackptr)->dirname != NULL)
1751 return (*stackptr)->dirname;
1752 else {
1753 ds_ptr = *stackptr;
1754 *stackptr = (*stackptr)->next;
1755 xfree(ds_ptr);
1756 return NULL;
1757 }
1758}
1759
1760
1761/*
1762 * pop dirbuf from the directory stack and return previous directory or NULL if
1763 * stack is empty
1764 */
1765static char_u *qf_pop_dir(struct dir_stack_T **stackptr)
1766{
1767 struct dir_stack_T *ds_ptr;
1768
1769 /* TODO: Should we check if dirbuf is the directory on top of the stack?
1770 * What to do if it isn't? */
1771
1772 /* pop top element and free it */
1773 if (*stackptr != NULL) {
1774 ds_ptr = *stackptr;
1775 *stackptr = (*stackptr)->next;
1776 xfree(ds_ptr->dirname);
1777 xfree(ds_ptr);
1778 }
1779
1780 /* return NEW top element as current dir or NULL if stack is empty*/
1781 return *stackptr ? (*stackptr)->dirname : NULL;
1782}
1783
1784/*
1785 * clean up directory stack
1786 */
1787static void qf_clean_dir_stack(struct dir_stack_T **stackptr)
1788{
1789 struct dir_stack_T *ds_ptr;
1790
1791 while ((ds_ptr = *stackptr) != NULL) {
1792 *stackptr = (*stackptr)->next;
1793 xfree(ds_ptr->dirname);
1794 xfree(ds_ptr);
1795 }
1796}
1797
1798/*
1799 * Check in which directory of the directory stack the given file can be
1800 * found.
1801 * Returns a pointer to the directory name or NULL if not found.
1802 * Cleans up intermediate directory entries.
1803 *
1804 * TODO: How to solve the following problem?
1805 * If we have the this directory tree:
1806 * ./
1807 * ./aa
1808 * ./aa/bb
1809 * ./bb
1810 * ./bb/x.c
1811 * and make says:
1812 * making all in aa
1813 * making all in bb
1814 * x.c:9: Error
1815 * Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb.
1816 * qf_guess_filepath will return NULL.
1817 */
1818static char_u *qf_guess_filepath(qf_info_T *qi, int qf_idx, char_u *filename)
1819{
1820 struct dir_stack_T *ds_ptr;
1821 struct dir_stack_T *ds_tmp;
1822 char_u *fullname;
1823 qf_list_T *qfl = &qi->qf_lists[qf_idx];
1824
1825 // no dirs on the stack - there's nothing we can do
1826 if (qfl->qf_dir_stack == NULL) {
1827 return NULL;
1828 }
1829
1830 ds_ptr = qfl->qf_dir_stack->next;
1831 fullname = NULL;
1832 while (ds_ptr) {
1833 xfree(fullname);
1834 fullname = (char_u *)concat_fnames((char *)ds_ptr->dirname, (char *)filename, TRUE);
1835
1836 if (os_path_exists(fullname)) {
1837 break;
1838 }
1839
1840 ds_ptr = ds_ptr->next;
1841 }
1842
1843 xfree(fullname);
1844
1845 // clean up all dirs we already left
1846 while (qfl->qf_dir_stack->next != ds_ptr) {
1847 ds_tmp = qfl->qf_dir_stack->next;
1848 qfl->qf_dir_stack->next = qfl->qf_dir_stack->next->next;
1849 xfree(ds_tmp->dirname);
1850 xfree(ds_tmp);
1851 }
1852
1853 return ds_ptr == NULL ? NULL : ds_ptr->dirname;
1854}
1855
1856/// Returns true, if a quickfix/location list with the given identifier exists.
1857static bool qflist_valid(win_T *wp, unsigned int qf_id)
1858{
1859 qf_info_T *qi = &ql_info;
1860
1861 if (wp) {
1862 qi = GET_LOC_LIST(wp);
1863 if (!qi) {
1864 return false;
1865 }
1866 }
1867
1868 for (int i = 0; i < qi->qf_listcount; i++) {
1869 if (qi->qf_lists[i].qf_id == qf_id) {
1870 return true;
1871 }
1872 }
1873
1874 return false;
1875}
1876
1877/// When loading a file from the quickfix, the autocommands may modify it.
1878/// This may invalidate the current quickfix entry. This function checks
1879/// whether a entry is still present in the quickfix.
1880/// Similar to location list.
1881static bool is_qf_entry_present(qf_info_T *qi, qfline_T *qf_ptr)
1882{
1883 qf_list_T *qfl;
1884 qfline_T *qfp;
1885 int i;
1886
1887 qfl = &qi->qf_lists[qi->qf_curlist];
1888
1889 // Search for the entry in the current list
1890 for (i = 0, qfp = qfl->qf_start; i < qfl->qf_count; i++, qfp = qfp->qf_next) {
1891 if (qfp == NULL || qfp == qf_ptr) {
1892 break;
1893 }
1894 }
1895
1896 if (i == qfl->qf_count) { // Entry is not found
1897 return false;
1898 }
1899
1900 return true;
1901}
1902
1903/// Get the next valid entry in the current quickfix/location list. The search
1904/// starts from the current entry. Returns NULL on failure.
1905static qfline_T *get_next_valid_entry(qf_info_T *qi, qfline_T *qf_ptr,
1906 int *qf_index, int dir)
1907{
1908 int idx = *qf_index;
1909 int old_qf_fnum = qf_ptr->qf_fnum;
1910
1911 do {
1912 if (idx == qi->qf_lists[qi->qf_curlist].qf_count
1913 || qf_ptr->qf_next == NULL) {
1914 return NULL;
1915 }
1916 idx++;
1917 qf_ptr = qf_ptr->qf_next;
1918 } while ((!qi->qf_lists[qi->qf_curlist].qf_nonevalid && !qf_ptr->qf_valid)
1919 || (dir == FORWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum));
1920
1921 *qf_index = idx;
1922 return qf_ptr;
1923}
1924
1925/// Get the previous valid entry in the current quickfix/location list. The
1926/// search starts from the current entry. Returns NULL on failure.
1927static qfline_T *get_prev_valid_entry(qf_info_T *qi, qfline_T *qf_ptr,
1928 int *qf_index, int dir)
1929{
1930 int idx = *qf_index;
1931 int old_qf_fnum = qf_ptr->qf_fnum;
1932
1933 do {
1934 if (idx == 1 || qf_ptr->qf_prev == NULL) {
1935 return NULL;
1936 }
1937 idx--;
1938 qf_ptr = qf_ptr->qf_prev;
1939 } while ((!qi->qf_lists[qi->qf_curlist].qf_nonevalid && !qf_ptr->qf_valid)
1940 || (dir == BACKWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum));
1941
1942 *qf_index = idx;
1943 return qf_ptr;
1944}
1945
1946/// Get the n'th (errornr) previous/next valid entry from the current entry in
1947/// the quickfix list.
1948/// dir == FORWARD or FORWARD_FILE: next valid entry
1949/// dir == BACKWARD or BACKWARD_FILE: previous valid entry
1950static qfline_T *get_nth_valid_entry(qf_info_T *qi, int errornr,
1951 qfline_T *qf_ptr, int *qf_index, int dir)
1952{
1953 qfline_T *prev_qf_ptr;
1954 int prev_index;
1955 static char_u *e_no_more_items = (char_u *)N_("E553: No more items");
1956 char_u *err = e_no_more_items;
1957
1958 while (errornr--) {
1959 prev_qf_ptr = qf_ptr;
1960 prev_index = *qf_index;
1961
1962 if (dir == FORWARD || dir == FORWARD_FILE) {
1963 qf_ptr = get_next_valid_entry(qi, qf_ptr, qf_index, dir);
1964 } else {
1965 qf_ptr = get_prev_valid_entry(qi, qf_ptr, qf_index, dir);
1966 }
1967
1968 if (qf_ptr == NULL) {
1969 qf_ptr = prev_qf_ptr;
1970 *qf_index = prev_index;
1971 if (err != NULL) {
1972 EMSG(_(err));
1973 return NULL;
1974 }
1975 break;
1976 }
1977
1978 err = NULL;
1979 }
1980
1981 return qf_ptr;
1982}
1983
1984/// Get n'th (errornr) quickfix entry
1985static qfline_T *get_nth_entry(qf_info_T *qi, int errornr, qfline_T *qf_ptr,
1986 int *cur_qfidx)
1987{
1988 int qf_idx = *cur_qfidx;
1989
1990 // New error number is less than the current error number
1991 while (errornr < qf_idx && qf_idx > 1 && qf_ptr->qf_prev != NULL) {
1992 qf_idx--;
1993 qf_ptr = qf_ptr->qf_prev;
1994 }
1995
1996 // New error number is greater than the current error number
1997 while (errornr > qf_idx
1998 && qf_idx < qi->qf_lists[qi->qf_curlist].qf_count
1999 && qf_ptr->qf_next != NULL) {
2000 qf_idx++;
2001 qf_ptr = qf_ptr->qf_next;
2002 }
2003
2004 *cur_qfidx = qf_idx;
2005 return qf_ptr;
2006}
2007
2008/// Find a help window or open one.
2009static int jump_to_help_window(qf_info_T *qi, int *opened_window)
2010{
2011 win_T *wp = NULL;
2012
2013 if (cmdmod.tab != 0) {
2014 wp = NULL;
2015 } else {
2016 FOR_ALL_WINDOWS_IN_TAB(wp2, curtab) {
2017 if (bt_help(wp2->w_buffer)) {
2018 wp = wp2;
2019 break;
2020 }
2021 }
2022 }
2023
2024 if (wp != NULL && wp->w_buffer->b_nwindows > 0) {
2025 win_enter(wp, true);
2026 } else {
2027 // Split off help window; put it at far top if no position
2028 // specified, the current window is vertically split and narrow.
2029 int flags = WSP_HELP;
2030 if (cmdmod.split == 0
2031 && curwin->w_width != Columns
2032 && curwin->w_width < 80) {
2033 flags |= WSP_TOP;
2034 }
2035
2036 if (IS_LL_STACK(qi)) {
2037 flags |= WSP_NEWLOC; // don't copy the location list
2038 }
2039
2040 if (win_split(0, flags) == FAIL) {
2041 return FAIL;
2042 }
2043
2044 *opened_window = true;
2045
2046 if (curwin->w_height < p_hh) {
2047 win_setheight((int)p_hh);
2048 }
2049
2050 if (IS_LL_STACK(qi)) { // not a quickfix list
2051 // The new window should use the supplied location list
2052 curwin->w_llist = qi;
2053 qi->qf_refcount++;
2054 }
2055 }
2056
2057 if (!p_im) {
2058 restart_edit = 0; // don't want insert mode in help file
2059 }
2060
2061 return OK;
2062}
2063
2064/// Find a suitable window for opening a file (qf_fnum) and jump to it.
2065/// If the file is already opened in a window, jump to it.
2066static int qf_jump_to_usable_window(int qf_fnum, int *opened_window)
2067{
2068 win_T *usable_win_ptr = NULL;
2069 int usable_win;
2070 int flags;
2071 win_T *win;
2072 win_T *altwin;
2073
2074 usable_win = 0;
2075
2076 qf_info_T *ll_ref = curwin->w_llist_ref;
2077 if (ll_ref != NULL) {
2078 // Find a window using the same location list that is not a
2079 // quickfix window.
2080 FOR_ALL_WINDOWS_IN_TAB(usable_win_ptr2, curtab) {
2081 if (usable_win_ptr2->w_llist == ll_ref
2082 && !bt_quickfix(usable_win_ptr2->w_buffer)) {
2083 usable_win_ptr = usable_win_ptr2;
2084 usable_win = 1;
2085 break;
2086 }
2087 }
2088 }
2089
2090 if (!usable_win) {
2091 // Locate a window showing a normal buffer
2092 FOR_ALL_WINDOWS_IN_TAB(win2, curtab) {
2093 if (win2->w_buffer->b_p_bt[0] == NUL) {
2094 usable_win = 1;
2095 break;
2096 }
2097 }
2098 }
2099
2100 // If no usable window is found and 'switchbuf' contains "usetab"
2101 // then search in other tabs.
2102 if (!usable_win && (swb_flags & SWB_USETAB)) {
2103 FOR_ALL_TAB_WINDOWS(tp, wp) {
2104 if (wp->w_buffer->b_fnum == qf_fnum) {
2105 goto_tabpage_win(tp, wp);
2106 usable_win = 1;
2107 goto win_found;
2108 }
2109 }
2110 }
2111win_found:
2112
2113 // If there is only one window and it is the quickfix window, create a
2114 // new one above the quickfix window.
2115 if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win) {
2116 flags = WSP_ABOVE;
2117 if (ll_ref != NULL) {
2118 flags |= WSP_NEWLOC;
2119 }
2120 if (win_split(0, flags) == FAIL) {
2121 return FAIL; // not enough room for window
2122 }
2123 *opened_window = true; // close it when fail
2124 p_swb = empty_option; // don't split again
2125 swb_flags = 0;
2126 RESET_BINDING(curwin);
2127 if (ll_ref != NULL) {
2128 // The new window should use the location list from the
2129 // location list window
2130 curwin->w_llist = ll_ref;
2131 ll_ref->qf_refcount++;
2132 }
2133 } else {
2134 if (curwin->w_llist_ref != NULL) {
2135 // In a location window
2136 win = usable_win_ptr;
2137 if (win == NULL) {
2138 // Find the window showing the selected file
2139 FOR_ALL_WINDOWS_IN_TAB(win2, curtab) {
2140 if (win2->w_buffer->b_fnum == qf_fnum) {
2141 win = win2;
2142 break;
2143 }
2144 }
2145 if (win == NULL) {
2146 // Find a previous usable window
2147 win = curwin;
2148 do {
2149 if (win->w_buffer->b_p_bt[0] == NUL) {
2150 break;
2151 }
2152 if (win->w_prev == NULL) {
2153 win = lastwin; // wrap around the top
2154 } else {
2155 win = win->w_prev; // go to previous window
2156 }
2157 } while (win != curwin);
2158 }
2159 }
2160 win_goto(win);
2161
2162 // If the location list for the window is not set, then set it
2163 // to the location list from the location window
2164 if (win->w_llist == NULL) {
2165 win->w_llist = ll_ref;
2166 if (ll_ref != NULL) {
2167 ll_ref->qf_refcount++;
2168 }
2169 }
2170 } else {
2171 // Try to find a window that shows the right buffer.
2172 // Default to the window just above the quickfix buffer.
2173 win = curwin;
2174 altwin = NULL;
2175 for (;;) {
2176 if (win->w_buffer->b_fnum == qf_fnum) {
2177 break;
2178 }
2179 if (win->w_prev == NULL) {
2180 win = lastwin; // wrap around the top
2181 } else {
2182 win = win->w_prev; // go to previous window
2183 }
2184 if (IS_QF_WINDOW(win)) {
2185 // Didn't find it, go to the window before the quickfix window.
2186 if (altwin != NULL) {
2187 win = altwin;
2188 } else if (curwin->w_prev != NULL) {
2189 win = curwin->w_prev;
2190 } else {
2191 win = curwin->w_next;
2192 }
2193 break;
2194 }
2195
2196 // Remember a usable window.
2197 if (altwin == NULL && !win->w_p_pvw
2198 && win->w_buffer->b_p_bt[0] == NUL) {
2199 altwin = win;
2200 }
2201 }
2202
2203 win_goto(win);
2204 }
2205 }
2206
2207 return OK;
2208}
2209
2210/// Edit the selected file or help file.
2211static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit,
2212 win_T *oldwin, int *opened_window, int *abort)
2213{
2214 int retval = OK;
2215
2216 if (qf_ptr->qf_type == 1) {
2217 // Open help file (do_ecmd() will set b_help flag, readfile() will
2218 // set b_p_ro flag).
2219 if (!can_abandon(curbuf, forceit)) {
2220 no_write_message();
2221 retval = FAIL;
2222 } else {
2223 retval = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1,
2224 ECMD_HIDE + ECMD_SET_HELP,
2225 oldwin == curwin ? curwin : NULL);
2226 }
2227 } else {
2228 unsigned save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
2229
2230 retval = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1,
2231 GETF_SETMARK | GETF_SWITCH, forceit);
2232
2233 if (IS_LL_STACK(qi)) {
2234 // Location list. Check whether the associated window is still
2235 // present and the list is still valid.
2236 if (!win_valid_any_tab(oldwin)) {
2237 EMSG(_("E924: Current window was closed"));
2238 *abort = true;
2239 *opened_window = false;
2240 } else if (!qflist_valid(oldwin, save_qfid)) {
2241 EMSG(_(e_loc_list_changed));
2242 *abort = true;
2243 }
2244 } else if (!is_qf_entry_present(qi, qf_ptr)) {
2245 if (IS_QF_STACK(qi)) {
2246 EMSG(_("E925: Current quickfix was changed"));
2247 } else {
2248 EMSG(_(e_loc_list_changed));
2249 }
2250 *abort = true;
2251 }
2252
2253 if (*abort) {
2254 retval = FAIL;
2255 }
2256 }
2257
2258 return retval;
2259}
2260
2261/// Goto the error line in the current file using either line/column number or a
2262/// search pattern.
2263static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char_u qf_viscol,
2264 char_u *qf_pattern)
2265{
2266 linenr_T i;
2267 char_u *line;
2268 colnr_T screen_col;
2269 colnr_T char_col;
2270
2271 if (qf_pattern == NULL) {
2272 // Go to line with error, unless qf_lnum is 0.
2273 i = qf_lnum;
2274 if (i > 0) {
2275 if (i > curbuf->b_ml.ml_line_count) {
2276 i = curbuf->b_ml.ml_line_count;
2277 }
2278 curwin->w_cursor.lnum = i;
2279 }
2280 if (qf_col > 0) {
2281 curwin->w_cursor.col = qf_col - 1;
2282 curwin->w_cursor.coladd = 0;
2283 if (qf_viscol == true) {
2284 // Check each character from the beginning of the error
2285 // line up to the error column. For each tab character
2286 // found, reduce the error column value by the length of
2287 // a tab character.
2288 line = get_cursor_line_ptr();
2289 screen_col = 0;
2290 for (char_col = 0; char_col < curwin->w_cursor.col; char_col++) {
2291 if (*line == NUL) {
2292 break;
2293 }
2294 if (*line++ == '\t') {
2295 curwin->w_cursor.col -= 7 - (screen_col % 8);
2296 screen_col += 8 - (screen_col % 8);
2297 } else {
2298 screen_col++;
2299 }
2300 }
2301 }
2302 check_cursor();
2303 } else {
2304 beginline(BL_WHITE | BL_FIX);
2305 }
2306 } else {
2307 // Move the cursor to the first line in the buffer
2308 pos_T save_cursor = curwin->w_cursor;
2309 curwin->w_cursor.lnum = 0;
2310 if (!do_search(NULL, '/', qf_pattern, (long)1, SEARCH_KEEP, NULL, NULL)) {
2311 curwin->w_cursor = save_cursor;
2312 }
2313 }
2314}
2315
2316/// Display quickfix list index and size message
2317static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr,
2318 buf_T *old_curbuf, linenr_T old_lnum)
2319{
2320 // Update the screen before showing the message, unless the screen
2321 // scrolled up.
2322 if (!msg_scrolled) {
2323 update_topline_redraw();
2324 }
2325 snprintf((char *)IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index,
2326 qi->qf_lists[qi->qf_curlist].qf_count,
2327 qf_ptr->qf_cleared ? _(" (line deleted)") : "",
2328 (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
2329 // Add the message, skipping leading whitespace and newlines.
2330 int len = (int)STRLEN(IObuff);
2331 qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len);
2332
2333 // Output the message. Overwrite to avoid scrolling when the 'O'
2334 // flag is present in 'shortmess'; But when not jumping, print the
2335 // whole message.
2336 linenr_T i = msg_scroll;
2337 if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum) {
2338 msg_scroll = true;
2339 } else if (!msg_scrolled && shortmess(SHM_OVERALL)) {
2340 msg_scroll = false;
2341 }
2342 msg_ext_set_kind("quickfix");
2343 msg_attr_keep(IObuff, 0, true, false);
2344 msg_scroll = (int)i;
2345}
2346
2347/// jump to a quickfix line
2348/// if dir == FORWARD go "errornr" valid entries forward
2349/// if dir == BACKWARD go "errornr" valid entries backward
2350/// if dir == FORWARD_FILE go "errornr" valid entries files backward
2351/// if dir == BACKWARD_FILE go "errornr" valid entries files backward
2352/// else if "errornr" is zero, redisplay the same line
2353/// else go to entry "errornr"
2354void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
2355{
2356 qfline_T *qf_ptr;
2357 qfline_T *old_qf_ptr;
2358 int qf_index;
2359 int old_qf_index;
2360 buf_T *old_curbuf;
2361 linenr_T old_lnum;
2362 char_u *old_swb = p_swb;
2363 unsigned old_swb_flags = swb_flags;
2364 int opened_window = false;
2365 win_T *oldwin = curwin;
2366 int print_message = true;
2367 const bool old_KeyTyped = KeyTyped; // getting file may reset it
2368 int retval = OK;
2369
2370 if (qi == NULL)
2371 qi = &ql_info;
2372
2373 if (qi->qf_curlist >= qi->qf_listcount
2374 || qi->qf_lists[qi->qf_curlist].qf_count == 0) {
2375 EMSG(_(e_quickfix));
2376 return;
2377 }
2378
2379 qf_ptr = qi->qf_lists[qi->qf_curlist].qf_ptr;
2380 old_qf_ptr = qf_ptr;
2381 qf_index = qi->qf_lists[qi->qf_curlist].qf_index;
2382 old_qf_index = qf_index;
2383 if (dir != 0) { // next/prev valid entry
2384 qf_ptr = get_nth_valid_entry(qi, errornr, qf_ptr, &qf_index, dir);
2385 if (qf_ptr == NULL) {
2386 qf_ptr = old_qf_ptr;
2387 qf_index = old_qf_index;
2388 goto theend; // The horror... the horror...
2389 }
2390 } else if (errornr != 0) { // go to specified number
2391 qf_ptr = get_nth_entry(qi, errornr, qf_ptr, &qf_index);
2392 }
2393
2394 qi->qf_lists[qi->qf_curlist].qf_index = qf_index;
2395 if (qf_win_pos_update(qi, old_qf_index))
2396 /* No need to print the error message if it's visible in the error
2397 * window */
2398 print_message = FALSE;
2399
2400 // For ":helpgrep" find a help window or open one.
2401 if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) {
2402 if (jump_to_help_window(qi, &opened_window) == FAIL) {
2403 goto theend;
2404 }
2405 }
2406
2407 // If currently in the quickfix window, find another window to show the
2408 // file in.
2409 if (bt_quickfix(curbuf) && !opened_window) {
2410 // If there is no file specified, we don't know where to go.
2411 // But do advance, otherwise ":cn" gets stuck.
2412 if (qf_ptr->qf_fnum == 0) {
2413 goto theend;
2414 }
2415 if (qf_jump_to_usable_window(qf_ptr->qf_fnum, &opened_window) == FAIL) {
2416 goto failed;
2417 }
2418 }
2419
2420 /*
2421 * If there is a file name,
2422 * read the wanted file if needed, and check autowrite etc.
2423 */
2424 old_curbuf = curbuf;
2425 old_lnum = curwin->w_cursor.lnum;
2426
2427 if (qf_ptr->qf_fnum != 0) {
2428 int abort = false;
2429 retval = qf_jump_edit_buffer(qi, qf_ptr, forceit, oldwin, &opened_window,
2430 &abort);
2431 if (abort) {
2432 qi = NULL;
2433 qf_ptr = NULL;
2434 }
2435 }
2436
2437 if (retval == OK) {
2438 // When not switched to another buffer, still need to set pc mark
2439 if (curbuf == old_curbuf) {
2440 setpcmark();
2441 }
2442
2443 if (qf_ptr != NULL) {
2444 qf_jump_goto_line(qf_ptr->qf_lnum, qf_ptr->qf_col, qf_ptr->qf_viscol,
2445 qf_ptr->qf_pattern);
2446 }
2447
2448 if ((fdo_flags & FDO_QUICKFIX) && old_KeyTyped)
2449 foldOpenCursor();
2450 if (print_message) {
2451 qf_jump_print_msg(qi, qf_index, qf_ptr, old_curbuf, old_lnum);
2452 }
2453 } else {
2454 if (opened_window) {
2455 win_close(curwin, true); // Close opened window
2456 }
2457 if (qf_ptr != NULL && qf_ptr->qf_fnum != 0) {
2458 // Couldn't open file, so put index back where it was. This could
2459 // happen if the file was readonly and we changed something.
2460failed:
2461 qf_ptr = old_qf_ptr;
2462 qf_index = old_qf_index;
2463 }
2464 }
2465theend:
2466 if (qi != NULL) {
2467 qi->qf_lists[qi->qf_curlist].qf_ptr = qf_ptr;
2468 qi->qf_lists[qi->qf_curlist].qf_index = qf_index;
2469 }
2470 if (p_swb != old_swb && opened_window) {
2471 /* Restore old 'switchbuf' value, but not when an autocommand or
2472 * modeline has changed the value. */
2473 if (p_swb == empty_option) {
2474 p_swb = old_swb;
2475 swb_flags = old_swb_flags;
2476 } else
2477 free_string_option(old_swb);
2478 }
2479}
2480
2481/*
2482 * ":clist": list all errors
2483 * ":llist": list all locations
2484 */
2485void qf_list(exarg_T *eap)
2486{
2487 buf_T *buf;
2488 char_u *fname;
2489 qfline_T *qfp;
2490 int i;
2491 int idx1 = 1;
2492 int idx2 = -1;
2493 char_u *arg = eap->arg;
2494 int qfFileAttr;
2495 int qfSepAttr;
2496 int qfLineAttr;
2497 int all = eap->forceit; // if not :cl!, only show
2498 // recognised errors
2499 qf_info_T *qi = &ql_info;
2500
2501 if (eap->cmdidx == CMD_llist) {
2502 qi = GET_LOC_LIST(curwin);
2503 if (qi == NULL) {
2504 EMSG(_(e_loclist));
2505 return;
2506 }
2507 }
2508
2509 if (qi->qf_curlist >= qi->qf_listcount
2510 || qi->qf_lists[qi->qf_curlist].qf_count == 0) {
2511 EMSG(_(e_quickfix));
2512 return;
2513 }
2514
2515 bool plus = false;
2516 if (*arg == '+') {
2517 arg++;
2518 plus = true;
2519 }
2520 if (!get_list_range(&arg, &idx1, &idx2) || *arg != NUL) {
2521 EMSG(_(e_trailing));
2522 return;
2523 }
2524 if (plus) {
2525 i = qi->qf_lists[qi->qf_curlist].qf_index;
2526 idx2 = i + idx1;
2527 idx1 = i;
2528 } else {
2529 i = qi->qf_lists[qi->qf_curlist].qf_count;
2530 if (idx1 < 0) {
2531 idx1 = (-idx1 > i) ? 0 : idx1 + i + 1;
2532 }
2533 if (idx2 < 0) {
2534 idx2 = (-idx2 > i) ? 0 : idx2 + i + 1;
2535 }
2536 }
2537
2538 // Shorten all the file names, so that it is easy to read.
2539 shorten_fnames(false);
2540
2541 // Get the attributes for the different quickfix highlight items. Note
2542 // that this depends on syntax items defined in the qf.vim syntax file
2543 qfFileAttr = syn_name2attr((char_u *)"qfFileName");
2544 if (qfFileAttr == 0) {
2545 qfFileAttr = HL_ATTR(HLF_D);
2546 }
2547 qfSepAttr = syn_name2attr((char_u *)"qfSeparator");
2548 if (qfSepAttr == 0) {
2549 qfSepAttr = HL_ATTR(HLF_D);
2550 }
2551 qfLineAttr = syn_name2attr((char_u *)"qfLineNr");
2552 if (qfLineAttr == 0) {
2553 qfLineAttr = HL_ATTR(HLF_N);
2554 }
2555
2556 if (qi->qf_lists[qi->qf_curlist].qf_nonevalid) {
2557 all = true;
2558 }
2559 qfp = qi->qf_lists[qi->qf_curlist].qf_start;
2560 for (i = 1; !got_int && i <= qi->qf_lists[qi->qf_curlist].qf_count; ) {
2561 if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2) {
2562 if (got_int) {
2563 break;
2564 }
2565
2566 fname = NULL;
2567 if (qfp->qf_module != NULL && *qfp->qf_module != NUL) {
2568 vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", i,
2569 (char *)qfp->qf_module);
2570 } else {
2571 if (qfp->qf_fnum != 0 && (buf = buflist_findnr(qfp->qf_fnum)) != NULL) {
2572 fname = buf->b_fname;
2573 if (qfp->qf_type == 1) { // :helpgrep
2574 fname = path_tail(fname);
2575 }
2576 }
2577 if (fname == NULL) {
2578 snprintf((char *)IObuff, IOSIZE, "%2d", i);
2579 } else {
2580 vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", i, (char *)fname);
2581 }
2582 }
2583
2584 // Support for filtering entries using :filter /pat/ clist
2585 // Match against the module name, file name, search pattern and
2586 // text of the entry.
2587 bool filter_entry = true;
2588 if (qfp->qf_module != NULL && *qfp->qf_module != NUL) {
2589 filter_entry &= message_filtered(qfp->qf_module);
2590 }
2591 if (filter_entry && fname != NULL) {
2592 filter_entry &= message_filtered(fname);
2593 }
2594 if (filter_entry && qfp->qf_pattern != NULL) {
2595 filter_entry &= message_filtered(qfp->qf_pattern);
2596 }
2597 if (filter_entry) {
2598 filter_entry &= message_filtered(qfp->qf_text);
2599 }
2600 if (filter_entry) {
2601 goto next_entry;
2602 }
2603 msg_putchar('\n');
2604 msg_outtrans_attr(IObuff, i == qi->qf_lists[qi->qf_curlist].qf_index
2605 ? HL_ATTR(HLF_QFL) : qfFileAttr);
2606
2607 if (qfp->qf_lnum != 0) {
2608 msg_puts_attr(":", qfSepAttr);
2609 }
2610 if (qfp->qf_lnum == 0) {
2611 IObuff[0] = NUL;
2612 } else if (qfp->qf_col == 0) {
2613 vim_snprintf((char *)IObuff, IOSIZE, "%" PRIdLINENR, qfp->qf_lnum);
2614 } else {
2615 vim_snprintf((char *)IObuff, IOSIZE, "%" PRIdLINENR " col %d",
2616 qfp->qf_lnum, qfp->qf_col);
2617 }
2618 vim_snprintf((char *)IObuff + STRLEN(IObuff), IOSIZE, "%s",
2619 (char *)qf_types(qfp->qf_type, qfp->qf_nr));
2620 msg_puts_attr((const char *)IObuff, qfLineAttr);
2621 msg_puts_attr(":", qfSepAttr);
2622 if (qfp->qf_pattern != NULL) {
2623 qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE);
2624 msg_puts((const char *)IObuff);
2625 msg_puts_attr(":", qfSepAttr);
2626 }
2627 msg_puts(" ");
2628
2629 /* Remove newlines and leading whitespace from the text. For an
2630 * unrecognized line keep the indent, the compiler may mark a word
2631 * with ^^^^. */
2632 qf_fmt_text((fname != NULL || qfp->qf_lnum != 0)
2633 ? skipwhite(qfp->qf_text) : qfp->qf_text,
2634 IObuff, IOSIZE);
2635 msg_prt_line(IObuff, FALSE);
2636 ui_flush(); /* show one line at a time */
2637 }
2638
2639next_entry:
2640 qfp = qfp->qf_next;
2641 if (qfp == NULL) {
2642 break;
2643 }
2644 i++;
2645 os_breakcheck();
2646 }
2647}
2648
2649/*
2650 * Remove newlines and leading whitespace from an error message.
2651 * Put the result in "buf[bufsize]".
2652 */
2653static void qf_fmt_text(char_u *text, char_u *buf, int bufsize)
2654{
2655 int i;
2656 char_u *p = text;
2657
2658 for (i = 0; *p != NUL && i < bufsize - 1; ++i) {
2659 if (*p == '\n') {
2660 buf[i] = ' ';
2661 while (*++p != NUL)
2662 if (!ascii_iswhite(*p) && *p != '\n')
2663 break;
2664 } else
2665 buf[i] = *p++;
2666 }
2667 buf[i] = NUL;
2668}
2669
2670/// Display information (list number, list size and the title) about a
2671/// quickfix/location list.
2672static void qf_msg(qf_info_T *qi, int which, char *lead)
2673{
2674 char *title = (char *)qi->qf_lists[which].qf_title;
2675 int count = qi->qf_lists[which].qf_count;
2676 char_u buf[IOSIZE];
2677
2678 vim_snprintf((char *)buf, IOSIZE, _("%serror list %d of %d; %d errors "),
2679 lead,
2680 which + 1,
2681 qi->qf_listcount,
2682 count);
2683
2684 if (title != NULL) {
2685 size_t len = STRLEN(buf);
2686
2687 if (len < 34) {
2688 memset(buf + len, ' ', 34 - len);
2689 buf[34] = NUL;
2690 }
2691 xstrlcat((char *)buf, title, IOSIZE);
2692 }
2693 trunc_string(buf, buf, Columns - 1, IOSIZE);
2694 msg(buf);
2695}
2696
2697/*
2698 * ":colder [count]": Up in the quickfix stack.
2699 * ":cnewer [count]": Down in the quickfix stack.
2700 * ":lolder [count]": Up in the location list stack.
2701 * ":lnewer [count]": Down in the location list stack.
2702 */
2703void qf_age(exarg_T *eap)
2704{
2705 qf_info_T *qi = &ql_info;
2706 int count;
2707
2708 if (eap->cmdidx == CMD_lolder || eap->cmdidx == CMD_lnewer) {
2709 qi = GET_LOC_LIST(curwin);
2710 if (qi == NULL) {
2711 EMSG(_(e_loclist));
2712 return;
2713 }
2714 }
2715
2716 if (eap->addr_count != 0) {
2717 assert(eap->line2 <= INT_MAX);
2718 count = (int)eap->line2;
2719 } else {
2720 count = 1;
2721 }
2722 while (count--) {
2723 if (eap->cmdidx == CMD_colder || eap->cmdidx == CMD_lolder) {
2724 if (qi->qf_curlist == 0) {
2725 EMSG(_("E380: At bottom of quickfix stack"));
2726 break;
2727 }
2728 --qi->qf_curlist;
2729 } else {
2730 if (qi->qf_curlist >= qi->qf_listcount - 1) {
2731 EMSG(_("E381: At top of quickfix stack"));
2732 break;
2733 }
2734 ++qi->qf_curlist;
2735 }
2736 }
2737 qf_msg(qi, qi->qf_curlist, "");
2738 qf_update_buffer(qi, NULL);
2739}
2740
2741/// Display the information about all the quickfix/location lists in the stack.
2742void qf_history(exarg_T *eap)
2743{
2744 qf_info_T *qi = &ql_info;
2745 int i;
2746
2747 if (eap->cmdidx == CMD_lhistory) {
2748 qi = GET_LOC_LIST(curwin);
2749 }
2750 if (qi == NULL || (qi->qf_listcount == 0
2751 && qi->qf_lists[qi->qf_curlist].qf_count == 0)) {
2752 MSG(_("No entries"));
2753 } else {
2754 for (i = 0; i < qi->qf_listcount; i++) {
2755 qf_msg(qi, i, i == qi->qf_curlist ? "> " : " ");
2756 }
2757 }
2758}
2759
2760/// Free all the entries in the error list "idx". Note that other information
2761/// associated with the list like context and title are not freed.
2762static void qf_free_items(qf_info_T *qi, int idx)
2763{
2764 qfline_T *qfp;
2765 qfline_T *qfpnext;
2766 bool stop = false;
2767 qf_list_T *qfl = &qi->qf_lists[idx];
2768
2769 while (qfl->qf_count && qfl->qf_start != NULL) {
2770 qfp = qfl->qf_start;
2771 qfpnext = qfp->qf_next;
2772 if (!stop) {
2773 xfree(qfp->qf_module);
2774 xfree(qfp->qf_text);
2775 xfree(qfp->qf_pattern);
2776 stop = (qfp == qfpnext);
2777 xfree(qfp);
2778 if (stop) {
2779 // Somehow qf_count may have an incorrect value, set it to 1
2780 // to avoid crashing when it's wrong.
2781 // TODO(vim): Avoid qf_count being incorrect.
2782 qfl->qf_count = 1;
2783 }
2784 }
2785 qfl->qf_start = qfpnext;
2786 qfl->qf_count--;
2787 }
2788
2789 qfl->qf_start = NULL;
2790 qfl->qf_ptr = NULL;
2791 qfl->qf_index = 0;
2792 qfl->qf_start = NULL;
2793 qfl->qf_last = NULL;
2794 qfl->qf_ptr = NULL;
2795 qfl->qf_nonevalid = true;
2796
2797 qf_clean_dir_stack(&qfl->qf_dir_stack);
2798 qfl->qf_directory = NULL;
2799 qf_clean_dir_stack(&qfl->qf_file_stack);
2800 qfl->qf_currfile = NULL;
2801 qfl->qf_multiline = false;
2802 qfl->qf_multiignore = false;
2803 qfl->qf_multiscan = false;
2804}
2805
2806/// Free error list "idx". Frees all the entries in the quickfix list,
2807/// associated context information and the title.
2808static void qf_free(qf_info_T *qi, int idx)
2809{
2810 qf_list_T *qfl = &qi->qf_lists[idx];
2811 qf_free_items(qi, idx);
2812
2813 XFREE_CLEAR(qfl->qf_title);
2814 tv_free(qfl->qf_ctx);
2815 qfl->qf_ctx = NULL;
2816 qfl->qf_id = 0;
2817 qfl->qf_changedtick = 0L;
2818}
2819
2820/*
2821 * qf_mark_adjust: adjust marks
2822 */
2823bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount,
2824 long amount_after)
2825{
2826 int i;
2827 qfline_T *qfp;
2828 int idx;
2829 qf_info_T *qi = &ql_info;
2830 bool found_one = false;
2831 int buf_has_flag = wp == NULL ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
2832
2833 if (!(curbuf->b_has_qf_entry & buf_has_flag)) {
2834 return false;
2835 }
2836 if (wp != NULL) {
2837 if (wp->w_llist == NULL) {
2838 return false;
2839 }
2840 qi = wp->w_llist;
2841 }
2842
2843 for (idx = 0; idx < qi->qf_listcount; ++idx)
2844 if (qi->qf_lists[idx].qf_count)
2845 for (i = 0, qfp = qi->qf_lists[idx].qf_start;
2846 i < qi->qf_lists[idx].qf_count && qfp != NULL;
2847 i++, qfp = qfp->qf_next) {
2848 if (qfp->qf_fnum == curbuf->b_fnum) {
2849 found_one = true;
2850 if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) {
2851 if (amount == MAXLNUM)
2852 qfp->qf_cleared = TRUE;
2853 else
2854 qfp->qf_lnum += amount;
2855 } else if (amount_after && qfp->qf_lnum > line2)
2856 qfp->qf_lnum += amount_after;
2857 }
2858 }
2859
2860 return found_one;
2861}
2862
2863/*
2864 * Make a nice message out of the error character and the error number:
2865 * char number message
2866 * e or E 0 " error"
2867 * w or W 0 " warning"
2868 * i or I 0 " info"
2869 * 0 0 ""
2870 * other 0 " c"
2871 * e or E n " error n"
2872 * w or W n " warning n"
2873 * i or I n " info n"
2874 * 0 n " error n"
2875 * other n " c n"
2876 * 1 x "" :helpgrep
2877 */
2878static char_u *qf_types(int c, int nr)
2879{
2880 static char_u buf[20];
2881 static char_u cc[3];
2882 char_u *p;
2883
2884 if (c == 'W' || c == 'w')
2885 p = (char_u *)" warning";
2886 else if (c == 'I' || c == 'i')
2887 p = (char_u *)" info";
2888 else if (c == 'E' || c == 'e' || (c == 0 && nr > 0))
2889 p = (char_u *)" error";
2890 else if (c == 0 || c == 1)
2891 p = (char_u *)"";
2892 else {
2893 cc[0] = ' ';
2894 cc[1] = (char_u)c;
2895 cc[2] = NUL;
2896 p = cc;
2897 }
2898
2899 if (nr <= 0)
2900 return p;
2901
2902 sprintf((char *)buf, "%s %3d", (char *)p, nr);
2903 return buf;
2904}
2905
2906// When "split" is false: Open the entry/result under the cursor.
2907// When "split" is true: Open the entry/result under the cursor in a new window.
2908void qf_view_result(bool split)
2909{
2910 qf_info_T *qi = &ql_info;
2911
2912 if (!bt_quickfix(curbuf)) {
2913 return;
2914 }
2915 if (IS_LL_WINDOW(curwin)) {
2916 qi = GET_LOC_LIST(curwin);
2917 }
2918 if (qf_list_empty(qi, qi->qf_curlist)) {
2919 EMSG(_(e_quickfix));
2920 return;
2921 }
2922
2923 if (split) {
2924 char cmd[32];
2925
2926 snprintf(cmd, sizeof(cmd), "split +%" PRId64 "%s",
2927 (int64_t)curwin->w_cursor.lnum,
2928 IS_LL_WINDOW(curwin) ? "ll" : "cc");
2929 if (do_cmdline_cmd(cmd) == OK) {
2930 do_cmdline_cmd("clearjumps");
2931 }
2932 return;
2933 }
2934
2935 do_cmdline_cmd((IS_LL_WINDOW(curwin) ? ".ll" : ".cc"));
2936}
2937
2938/*
2939 * ":cwindow": open the quickfix window if we have errors to display,
2940 * close it if not.
2941 * ":lwindow": open the location list window if we have locations to display,
2942 * close it if not.
2943 */
2944void ex_cwindow(exarg_T *eap)
2945{
2946 qf_info_T *qi = &ql_info;
2947 win_T *win;
2948
2949 if (eap->cmdidx == CMD_lwindow) {
2950 qi = GET_LOC_LIST(curwin);
2951 if (qi == NULL)
2952 return;
2953 }
2954
2955 /* Look for an existing quickfix window. */
2956 win = qf_find_win(qi);
2957
2958 /*
2959 * If a quickfix window is open but we have no errors to display,
2960 * close the window. If a quickfix window is not open, then open
2961 * it if we have errors; otherwise, leave it closed.
2962 */
2963 if (qi->qf_lists[qi->qf_curlist].qf_nonevalid
2964 || qi->qf_lists[qi->qf_curlist].qf_count == 0
2965 || qi->qf_curlist >= qi->qf_listcount) {
2966 if (win != NULL)
2967 ex_cclose(eap);
2968 } else if (win == NULL)
2969 ex_copen(eap);
2970}
2971
2972/*
2973 * ":cclose": close the window showing the list of errors.
2974 * ":lclose": close the window showing the location list
2975 */
2976void ex_cclose(exarg_T *eap)
2977{
2978 win_T *win = NULL;
2979 qf_info_T *qi = &ql_info;
2980
2981 if (eap->cmdidx == CMD_lclose || eap->cmdidx == CMD_lwindow) {
2982 qi = GET_LOC_LIST(curwin);
2983 if (qi == NULL)
2984 return;
2985 }
2986
2987 /* Find existing quickfix window and close it. */
2988 win = qf_find_win(qi);
2989 if (win != NULL) {
2990 win_close(win, false);
2991 }
2992}
2993
2994/*
2995 * ":copen": open a window that shows the list of errors.
2996 * ":lopen": open a window that shows the location list.
2997 */
2998void ex_copen(exarg_T *eap)
2999{
3000 qf_info_T *qi = &ql_info;
3001 int height;
3002 win_T *win;
3003 tabpage_T *prevtab = curtab;
3004 buf_T *qf_buf;
3005 win_T *oldwin = curwin;
3006
3007 if (eap->cmdidx == CMD_lopen || eap->cmdidx == CMD_lwindow) {
3008 qi = GET_LOC_LIST(curwin);
3009 if (qi == NULL) {
3010 EMSG(_(e_loclist));
3011 return;
3012 }
3013 }
3014
3015 if (eap->addr_count != 0) {
3016 assert(eap->line2 <= INT_MAX);
3017 height = (int)eap->line2;
3018 } else {
3019 height = QF_WINHEIGHT;
3020 }
3021 reset_VIsual_and_resel(); // stop Visual mode
3022
3023 /*
3024 * Find existing quickfix window, or open a new one.
3025 */
3026 win = qf_find_win(qi);
3027
3028 if (win != NULL && cmdmod.tab == 0) {
3029 win_goto(win);
3030 if (eap->addr_count != 0) {
3031 if (cmdmod.split & WSP_VERT) {
3032 if (height != win->w_width) {
3033 win_setwidth(height);
3034 }
3035 } else {
3036 if (height != win->w_height) {
3037 win_setheight(height);
3038 }
3039 }
3040 }
3041 } else {
3042 int flags = 0;
3043
3044 qf_buf = qf_find_buf(qi);
3045
3046 /* The current window becomes the previous window afterwards. */
3047 win = curwin;
3048
3049 if ((eap->cmdidx == CMD_copen || eap->cmdidx == CMD_cwindow)
3050 && cmdmod.split == 0)
3051 // Create the new quickfix window at the very bottom, except when
3052 // :belowright or :aboveleft is used.
3053 win_goto(lastwin);
3054 // Default is to open the window below the current window
3055 if (cmdmod.split == 0) {
3056 flags = WSP_BELOW;
3057 }
3058 flags |= WSP_NEWLOC;
3059 if (win_split(height, flags) == FAIL) {
3060 return; // not enough room for window
3061 }
3062 RESET_BINDING(curwin);
3063
3064 if (eap->cmdidx == CMD_lopen || eap->cmdidx == CMD_lwindow) {
3065 /*
3066 * For the location list window, create a reference to the
3067 * location list from the window 'win'.
3068 */
3069 curwin->w_llist_ref = win->w_llist;
3070 win->w_llist->qf_refcount++;
3071 }
3072
3073 if (oldwin != curwin)
3074 oldwin = NULL; /* don't store info when in another window */
3075 if (qf_buf != NULL)
3076 /* Use the existing quickfix buffer */
3077 (void)do_ecmd(qf_buf->b_fnum, NULL, NULL, NULL, ECMD_ONE,
3078 ECMD_HIDE + ECMD_OLDBUF, oldwin);
3079 else {
3080 /* Create a new quickfix buffer */
3081 (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin);
3082 // Switch off 'swapfile'.
3083 set_option_value("swf", 0L, NULL, OPT_LOCAL);
3084 set_option_value("bt", 0L, "quickfix", OPT_LOCAL);
3085 set_option_value("bh", 0L, "wipe", OPT_LOCAL);
3086 RESET_BINDING(curwin);
3087 curwin->w_p_diff = false;
3088 set_option_value("fdm", 0L, "manual", OPT_LOCAL);
3089 }
3090
3091 /* Only set the height when still in the same tab page and there is no
3092 * window to the side. */
3093 if (curtab == prevtab
3094 && curwin->w_width == Columns
3095 )
3096 win_setheight(height);
3097 curwin->w_p_wfh = TRUE; /* set 'winfixheight' */
3098 if (win_valid(win))
3099 prevwin = win;
3100 }
3101
3102 qf_set_title_var(qi);
3103
3104 // Fill the buffer with the quickfix list.
3105 qf_fill_buffer(qi, curbuf, NULL);
3106
3107 curwin->w_cursor.lnum = qi->qf_lists[qi->qf_curlist].qf_index;
3108 curwin->w_cursor.col = 0;
3109 check_cursor();
3110 update_topline(); /* scroll to show the line */
3111}
3112
3113// Move the cursor in the quickfix window to "lnum".
3114static void qf_win_goto(win_T *win, linenr_T lnum)
3115{
3116 win_T *old_curwin = curwin;
3117
3118 curwin = win;
3119 curbuf = win->w_buffer;
3120 curwin->w_cursor.lnum = lnum;
3121 curwin->w_cursor.col = 0;
3122 curwin->w_cursor.coladd = 0;
3123 curwin->w_curswant = 0;
3124 update_topline(); // scroll to show the line
3125 redraw_later(VALID);
3126 curwin->w_redr_status = true; // update ruler
3127 curwin = old_curwin;
3128 curbuf = curwin->w_buffer;
3129}
3130
3131// :cbottom/:lbottom command.
3132void ex_cbottom(exarg_T *eap)
3133{
3134 qf_info_T *qi = &ql_info;
3135
3136 if (eap->cmdidx == CMD_lbottom) {
3137 qi = GET_LOC_LIST(curwin);
3138 if (qi == NULL) {
3139 EMSG(_(e_loclist));
3140 return;
3141 }
3142 }
3143
3144 win_T *win = qf_find_win(qi);
3145
3146 if (win != NULL && win->w_cursor.lnum != win->w_buffer->b_ml.ml_line_count) {
3147 qf_win_goto(win, win->w_buffer->b_ml.ml_line_count);
3148 }
3149}
3150
3151/*
3152 * Return the number of the current entry (line number in the quickfix
3153 * window).
3154 */
3155linenr_T qf_current_entry(win_T *wp)
3156{
3157 qf_info_T *qi = &ql_info;
3158
3159 if (IS_LL_WINDOW(wp))
3160 /* In the location list window, use the referenced location list */
3161 qi = wp->w_llist_ref;
3162
3163 return qi->qf_lists[qi->qf_curlist].qf_index;
3164}
3165
3166/*
3167 * Update the cursor position in the quickfix window to the current error.
3168 * Return TRUE if there is a quickfix window.
3169 */
3170static int
3171qf_win_pos_update (
3172 qf_info_T *qi,
3173 int old_qf_index /* previous qf_index or zero */
3174)
3175{
3176 win_T *win;
3177 int qf_index = qi->qf_lists[qi->qf_curlist].qf_index;
3178
3179 /*
3180 * Put the cursor on the current error in the quickfix window, so that
3181 * it's viewable.
3182 */
3183 win = qf_find_win(qi);
3184 if (win != NULL
3185 && qf_index <= win->w_buffer->b_ml.ml_line_count
3186 && old_qf_index != qf_index) {
3187 if (qf_index > old_qf_index) {
3188 win->w_redraw_top = old_qf_index;
3189 win->w_redraw_bot = qf_index;
3190 } else {
3191 win->w_redraw_top = qf_index;
3192 win->w_redraw_bot = old_qf_index;
3193 }
3194 qf_win_goto(win, qf_index);
3195 }
3196 return win != NULL;
3197}
3198
3199/// Checks whether the given window is displaying the specified
3200/// quickfix/location list buffer.
3201static int is_qf_win(win_T *win, qf_info_T *qi)
3202{
3203 //
3204 // A window displaying the quickfix buffer will have the w_llist_ref field
3205 // set to NULL.
3206 // A window displaying a location list buffer will have the w_llist_ref
3207 // pointing to the location list.
3208 //
3209 if (bt_quickfix(win->w_buffer)) {
3210 if ((IS_QF_STACK(qi) && win->w_llist_ref == NULL)
3211 || (IS_LL_STACK(qi) && win->w_llist_ref == qi)) {
3212 return true;
3213 }
3214 }
3215
3216 return false;
3217}
3218
3219/// Find a window displaying the quickfix/location list 'qi'
3220/// Only searches in the current tabpage.
3221static win_T *qf_find_win(qf_info_T *qi)
3222{
3223 FOR_ALL_WINDOWS_IN_TAB(win, curtab) {
3224 if (is_qf_win(win, qi)) {
3225 return win;
3226 }
3227 }
3228
3229 return NULL;
3230}
3231
3232/*
3233 * Find a quickfix buffer.
3234 * Searches in windows opened in all the tabs.
3235 */
3236static buf_T *qf_find_buf(qf_info_T *qi)
3237{
3238 FOR_ALL_TAB_WINDOWS(tp, win) {
3239 if (is_qf_win(win, qi)) {
3240 return win->w_buffer;
3241 }
3242 }
3243
3244 return NULL;
3245}
3246
3247/// Update the w:quickfix_title variable in the quickfix/location list window
3248static void qf_update_win_titlevar(qf_info_T *qi)
3249{
3250 win_T *win;
3251
3252 if ((win = qf_find_win(qi)) != NULL) {
3253 win_T *curwin_save = curwin;
3254 curwin = win;
3255 qf_set_title_var(qi);
3256 curwin = curwin_save;
3257 }
3258}
3259
3260/*
3261 * Find the quickfix buffer. If it exists, update the contents.
3262 */
3263static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
3264{
3265 buf_T *buf;
3266 win_T *win;
3267 aco_save_T aco;
3268
3269 /* Check if a buffer for the quickfix list exists. Update it. */
3270 buf = qf_find_buf(qi);
3271 if (buf != NULL) {
3272 linenr_T old_line_count = buf->b_ml.ml_line_count;
3273
3274 if (old_last == NULL) {
3275 // set curwin/curbuf to buf and save a few things
3276 aucmd_prepbuf(&aco, buf);
3277 }
3278
3279 qf_update_win_titlevar(qi);
3280
3281 qf_fill_buffer(qi, buf, old_last);
3282 buf_inc_changedtick(buf);
3283
3284 if (old_last == NULL) {
3285 (void)qf_win_pos_update(qi, 0);
3286
3287 // restore curwin/curbuf and a few other things
3288 aucmd_restbuf(&aco);
3289 }
3290
3291 // Only redraw when added lines are visible. This avoids flickering when
3292 // the added lines are not visible.
3293 if ((win = qf_find_win(qi)) != NULL && old_line_count < win->w_botline) {
3294 redraw_buf_later(buf, NOT_VALID);
3295 }
3296 }
3297}
3298
3299// Set "w:quickfix_title" if "qi" has a title.
3300static void qf_set_title_var(qf_info_T *qi)
3301{
3302 if (qi->qf_lists[qi->qf_curlist].qf_title != NULL) {
3303 set_internal_string_var((char_u *)"w:quickfix_title",
3304 qi->qf_lists[qi->qf_curlist].qf_title);
3305 }
3306}
3307
3308// Fill current buffer with quickfix errors, replacing any previous contents.
3309// curbuf must be the quickfix buffer!
3310// If "old_last" is not NULL append the items after this one.
3311// When "old_last" is NULL then "buf" must equal "curbuf"! Because ml_delete()
3312// is used and autocommands will be triggered.
3313static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
3314{
3315 linenr_T lnum;
3316 qfline_T *qfp;
3317 buf_T *errbuf;
3318 int len;
3319 const bool old_KeyTyped = KeyTyped;
3320
3321 if (old_last == NULL) {
3322 if (buf != curbuf) {
3323 internal_error("qf_fill_buffer()");
3324 return;
3325 }
3326
3327 // delete all existing lines
3328 while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) {
3329 (void)ml_delete((linenr_T)1, false);
3330 }
3331 }
3332
3333 /* Check if there is anything to display */
3334 if (qi->qf_curlist < qi->qf_listcount) {
3335 char_u dirname[MAXPATHL];
3336
3337 *dirname = NUL;
3338
3339 // Add one line for each error
3340 if (old_last == NULL) {
3341 qfp = qi->qf_lists[qi->qf_curlist].qf_start;
3342 lnum = 0;
3343 } else {
3344 qfp = old_last->qf_next;
3345 lnum = buf->b_ml.ml_line_count;
3346 }
3347 while (lnum < qi->qf_lists[qi->qf_curlist].qf_count) {
3348 if (qfp->qf_module != NULL) {
3349 STRCPY(IObuff, qfp->qf_module);
3350 len = (int)STRLEN(IObuff);
3351 } else if (qfp->qf_fnum != 0
3352 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
3353 && errbuf->b_fname != NULL) {
3354 if (qfp->qf_type == 1) { // :helpgrep
3355 STRLCPY(IObuff, path_tail(errbuf->b_fname), sizeof(IObuff));
3356 } else {
3357 // shorten the file name if not done already
3358 if (errbuf->b_sfname == NULL
3359 || path_is_absolute(errbuf->b_sfname)) {
3360 if (*dirname == NUL) {
3361 os_dirname(dirname, MAXPATHL);
3362 }
3363 shorten_buf_fname(errbuf, dirname, false);
3364 }
3365 STRLCPY(IObuff, errbuf->b_fname, sizeof(IObuff));
3366 }
3367 len = (int)STRLEN(IObuff);
3368 } else {
3369 len = 0;
3370 }
3371 IObuff[len++] = '|';
3372
3373 if (qfp->qf_lnum > 0) {
3374 sprintf((char *)IObuff + len, "%" PRId64, (int64_t)qfp->qf_lnum);
3375 len += (int)STRLEN(IObuff + len);
3376
3377 if (qfp->qf_col > 0) {
3378 sprintf((char *)IObuff + len, " col %d", qfp->qf_col);
3379 len += (int)STRLEN(IObuff + len);
3380 }
3381
3382 sprintf((char *)IObuff + len, "%s",
3383 (char *)qf_types(qfp->qf_type, qfp->qf_nr));
3384 len += (int)STRLEN(IObuff + len);
3385 } else if (qfp->qf_pattern != NULL) {
3386 qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len);
3387 len += (int)STRLEN(IObuff + len);
3388 }
3389 IObuff[len++] = '|';
3390 IObuff[len++] = ' ';
3391
3392 /* Remove newlines and leading whitespace from the text.
3393 * For an unrecognized line keep the indent, the compiler may
3394 * mark a word with ^^^^. */
3395 qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text,
3396 IObuff + len, IOSIZE - len);
3397
3398 if (ml_append_buf(buf, lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, false)
3399 == FAIL) {
3400 break;
3401 }
3402 lnum++;
3403 qfp = qfp->qf_next;
3404 if (qfp == NULL) {
3405 break;
3406 }
3407 }
3408 if (old_last == NULL) {
3409 // Delete the empty line which is now at the end
3410 (void)ml_delete(lnum + 1, false);
3411 }
3412 }
3413
3414 // Correct cursor position.
3415 check_lnums(true);
3416
3417 if (old_last == NULL) {
3418 // Set the 'filetype' to "qf" each time after filling the buffer. This
3419 // resembles reading a file into a buffer, it's more logical when using
3420 // autocommands.
3421 curbuf_lock++;
3422 set_option_value("ft", 0L, "qf", OPT_LOCAL);
3423 curbuf->b_p_ma = false;
3424
3425 keep_filetype = true; // don't detect 'filetype'
3426 apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL,
3427 false, curbuf);
3428 apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL,
3429 false, curbuf);
3430 keep_filetype = false;
3431 curbuf_lock--;
3432
3433 // make sure it will be redrawn
3434 redraw_curbuf_later(NOT_VALID);
3435 }
3436
3437 /* Restore KeyTyped, setting 'filetype' may reset it. */
3438 KeyTyped = old_KeyTyped;
3439}
3440
3441static void qf_list_changed(qf_info_T *qi, int qf_idx)
3442{
3443 qi->qf_lists[qf_idx].qf_changedtick++;
3444}
3445
3446/// Return the quickfix/location list number with the given identifier.
3447///
3448/// @returns -1 if list is not found.
3449static int qf_id2nr(const qf_info_T *const qi, const unsigned qfid)
3450{
3451 for (int qf_idx = 0; qf_idx < qi->qf_listcount; qf_idx++) {
3452 if (qi->qf_lists[qf_idx].qf_id == qfid) {
3453 return qf_idx;
3454 }
3455 }
3456 return INVALID_QFIDX;
3457}
3458
3459// If the current list is not "save_qfid" and we can find the list with that ID
3460// then make it the current list.
3461// This is used when autocommands may have changed the current list.
3462// Returns OK if successfully restored the list. Returns FAIL if the list with
3463// the specified identifier (save_qfid) is not found in the stack.
3464static int qf_restore_list(qf_info_T *qi, unsigned save_qfid)
3465 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
3466{
3467 if (qi->qf_lists[qi->qf_curlist].qf_id != save_qfid) {
3468 const int curlist = qf_id2nr(qi, save_qfid);
3469 if (curlist < 0) {
3470 // list is not present
3471 return FAIL;
3472 }
3473 qi->qf_curlist = curlist;
3474 }
3475 return OK;
3476}
3477
3478// Jump to the first entry if there is one.
3479static void qf_jump_first(qf_info_T *qi, unsigned save_qfid, int forceit)
3480 FUNC_ATTR_NONNULL_ALL
3481{
3482 if (qf_restore_list(qi, save_qfid) == FAIL) {
3483 return;
3484 }
3485 // Autocommands might have cleared the list, check for that
3486 if (!qf_list_empty(qi, qi->qf_curlist)) {
3487 qf_jump(qi, 0, 0, forceit);
3488 }
3489}
3490
3491/*
3492 * Return TRUE when using ":vimgrep" for ":grep".
3493 */
3494int grep_internal(cmdidx_T cmdidx)
3495{
3496 return (cmdidx == CMD_grep
3497 || cmdidx == CMD_lgrep
3498 || cmdidx == CMD_grepadd
3499 || cmdidx == CMD_lgrepadd)
3500 && STRCMP("internal",
3501 *curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0;
3502}
3503
3504/*
3505 * Used for ":make", ":lmake", ":grep", ":lgrep", ":grepadd", and ":lgrepadd"
3506 */
3507void ex_make(exarg_T *eap)
3508{
3509 char_u *fname;
3510 win_T *wp = NULL;
3511 qf_info_T *qi = &ql_info;
3512 int res;
3513 char_u *au_name = NULL;
3514 char_u *enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc;
3515
3516 /* Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal". */
3517 if (grep_internal(eap->cmdidx)) {
3518 ex_vimgrep(eap);
3519 return;
3520 }
3521
3522 switch (eap->cmdidx) {
3523 case CMD_make: au_name = (char_u *)"make"; break;
3524 case CMD_lmake: au_name = (char_u *)"lmake"; break;
3525 case CMD_grep: au_name = (char_u *)"grep"; break;
3526 case CMD_lgrep: au_name = (char_u *)"lgrep"; break;
3527 case CMD_grepadd: au_name = (char_u *)"grepadd"; break;
3528 case CMD_lgrepadd: au_name = (char_u *)"lgrepadd"; break;
3529 default: break;
3530 }
3531 if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
3532 curbuf->b_fname, true, curbuf)) {
3533 if (aborting()) {
3534 return;
3535 }
3536 }
3537
3538 if (eap->cmdidx == CMD_lmake || eap->cmdidx == CMD_lgrep
3539 || eap->cmdidx == CMD_lgrepadd)
3540 wp = curwin;
3541
3542 autowrite_all();
3543 fname = get_mef_name();
3544 if (fname == NULL)
3545 return;
3546 os_remove((char *)fname); // in case it's not unique
3547
3548 // If 'shellpipe' empty: don't redirect to 'errorfile'.
3549 const size_t len = (STRLEN(p_shq) * 2 + STRLEN(eap->arg) + 1
3550 + (*p_sp == NUL
3551 ? 0
3552 : STRLEN(p_sp) + STRLEN(fname) + 3));
3553 char *const cmd = xmalloc(len);
3554 snprintf(cmd, len, "%s%s%s", (char *)p_shq, (char *)eap->arg,
3555 (char *)p_shq);
3556 if (*p_sp != NUL) {
3557 append_redir(cmd, len, (char *) p_sp, (char *) fname);
3558 }
3559 // Output a newline if there's something else than the :make command that
3560 // was typed (in which case the cursor is in column 0).
3561 if (msg_col == 0) {
3562 msg_didout = false;
3563 }
3564 msg_start();
3565 MSG_PUTS(":!");
3566 msg_outtrans((char_u *)cmd); // show what we are doing
3567
3568 do_shell((char_u *)cmd, 0);
3569
3570
3571 res = qf_init(wp, fname, (eap->cmdidx != CMD_make
3572 && eap->cmdidx != CMD_lmake) ? p_gefm : p_efm,
3573 (eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd),
3574 qf_cmdtitle(*eap->cmdlinep), enc);
3575 if (wp != NULL) {
3576 qi = GET_LOC_LIST(wp);
3577 if (qi == NULL) {
3578 goto cleanup;
3579 }
3580 }
3581 if (res >= 0) {
3582 qf_list_changed(qi, qi->qf_curlist);
3583 }
3584 // Remember the current quickfix list identifier, so that we can
3585 // check for autocommands changing the current quickfix list.
3586 unsigned save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
3587 if (au_name != NULL) {
3588 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname, true,
3589 curbuf);
3590 }
3591 if (res > 0 && !eap->forceit && qflist_valid(wp, save_qfid)) {
3592 // display the first error
3593 qf_jump_first(qi, save_qfid, false);
3594 }
3595
3596cleanup:
3597 os_remove((char *)fname);
3598 xfree(fname);
3599 xfree(cmd);
3600}
3601
3602/*
3603 * Return the name for the errorfile, in allocated memory.
3604 * Find a new unique name when 'makeef' contains "##".
3605 * Returns NULL for error.
3606 */
3607static char_u *get_mef_name(void)
3608{
3609 char_u *p;
3610 char_u *name;
3611 static int start = -1;
3612 static int off = 0;
3613
3614 if (*p_mef == NUL) {
3615 name = vim_tempname();
3616 if (name == NULL)
3617 EMSG(_(e_notmp));
3618 return name;
3619 }
3620
3621 for (p = p_mef; *p; ++p)
3622 if (p[0] == '#' && p[1] == '#')
3623 break;
3624
3625 if (*p == NUL)
3626 return vim_strsave(p_mef);
3627
3628 /* Keep trying until the name doesn't exist yet. */
3629 for (;; ) {
3630 if (start == -1) {
3631 start = (int)os_get_pid();
3632 } else {
3633 off += 19;
3634 }
3635 name = xmalloc(STRLEN(p_mef) + 30);
3636 STRCPY(name, p_mef);
3637 sprintf((char *)name + (p - p_mef), "%d%d", start, off);
3638 STRCAT(name, p + 2);
3639 // Don't accept a symbolic link, it's a security risk.
3640 FileInfo file_info;
3641 bool file_or_link_found = os_fileinfo_link((char *)name, &file_info);
3642 if (!file_or_link_found) {
3643 break;
3644 }
3645 xfree(name);
3646 }
3647 return name;
3648}
3649
3650/// Returns the number of valid entries in the current quickfix/location list.
3651size_t qf_get_size(exarg_T *eap)
3652 FUNC_ATTR_NONNULL_ALL
3653{
3654 qf_info_T *qi = &ql_info;
3655 if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) {
3656 // Location list.
3657 qi = GET_LOC_LIST(curwin);
3658 if (qi == NULL) {
3659 return 0;
3660 }
3661 }
3662
3663 int prev_fnum = 0;
3664 size_t sz = 0;
3665 qfline_T *qfp;
3666 size_t i;
3667 assert(qi->qf_lists[qi->qf_curlist].qf_count >= 0);
3668 for (i = 0, qfp = qi->qf_lists[qi->qf_curlist].qf_start;
3669 i < (size_t)qi->qf_lists[qi->qf_curlist].qf_count && qfp != NULL;
3670 i++, qfp = qfp->qf_next) {
3671 if (!qfp->qf_valid) {
3672 continue;
3673 }
3674
3675 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo) {
3676 // Count all valid entries.
3677 sz++;
3678 } else if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum) {
3679 // Count the number of files.
3680 sz++;
3681 prev_fnum = qfp->qf_fnum;
3682 }
3683 }
3684
3685 return sz;
3686}
3687
3688/// Returns the current index of the quickfix/location list.
3689/// Returns 0 if there is an error.
3690size_t qf_get_cur_idx(exarg_T *eap)
3691 FUNC_ATTR_NONNULL_ALL
3692{
3693 qf_info_T *qi = &ql_info;
3694
3695 if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) {
3696 // Location list.
3697 qi = GET_LOC_LIST(curwin);
3698 if (qi == NULL) {
3699 return 0;
3700 }
3701 }
3702
3703 assert(qi->qf_lists[qi->qf_curlist].qf_index >= 0);
3704 return (size_t)qi->qf_lists[qi->qf_curlist].qf_index;
3705}
3706
3707/// Returns the current index in the quickfix/location list,
3708/// counting only valid entries.
3709/// Returns 1 if there are no valid entries.
3710int qf_get_cur_valid_idx(exarg_T *eap)
3711 FUNC_ATTR_NONNULL_ALL
3712{
3713 qf_info_T *qi = &ql_info;
3714
3715 if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) {
3716 // Location list.
3717 qi = GET_LOC_LIST(curwin);
3718 if (qi == NULL) {
3719 return 1;
3720 }
3721 }
3722
3723 qf_list_T *qfl = &qi->qf_lists[qi->qf_curlist];
3724
3725 // Check if the list has valid errors.
3726 if (qfl->qf_count <= 0 || qfl->qf_nonevalid) {
3727 return 1;
3728 }
3729
3730 int prev_fnum = 0;
3731 int eidx = 0;
3732 qfline_T *qfp;
3733 size_t i;
3734 assert(qfl->qf_index >= 0);
3735 for (i = 1, qfp = qfl->qf_start;
3736 i <= (size_t)qfl->qf_index && qfp != NULL;
3737 i++, qfp = qfp->qf_next) {
3738 if (!qfp->qf_valid) {
3739 continue;
3740 }
3741
3742 if (eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
3743 if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum) {
3744 // Count the number of files.
3745 eidx++;
3746 prev_fnum = qfp->qf_fnum;
3747 }
3748 } else {
3749 eidx++;
3750 }
3751 }
3752
3753 return eidx != 0 ? eidx : 1;
3754}
3755
3756/// Get the 'n'th valid error entry in the quickfix or location list.
3757///
3758/// Used by :cdo, :ldo, :cfdo and :lfdo commands.
3759/// For :cdo and :ldo, returns the 'n'th valid error entry.
3760/// For :cfdo and :lfdo, returns the 'n'th valid file entry.
3761static size_t qf_get_nth_valid_entry(qf_info_T *qi, size_t n, bool fdo)
3762 FUNC_ATTR_NONNULL_ALL
3763{
3764 qf_list_T *qfl = &qi->qf_lists[qi->qf_curlist];
3765
3766 // Check if the list has valid errors.
3767 if (qfl->qf_count <= 0 || qfl->qf_nonevalid) {
3768 return 1;
3769 }
3770
3771 int prev_fnum = 0;
3772 size_t eidx = 0;
3773 size_t i;
3774 qfline_T *qfp;
3775 assert(qfl->qf_count >= 0);
3776 for (i = 1, qfp = qfl->qf_start;
3777 i <= (size_t)qfl->qf_count && qfp != NULL;
3778 i++, qfp = qfp->qf_next) {
3779 if (qfp->qf_valid) {
3780 if (fdo) {
3781 if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum) {
3782 // Count the number of files.
3783 eidx++;
3784 prev_fnum = qfp->qf_fnum;
3785 }
3786 } else {
3787 eidx++;
3788 }
3789 }
3790
3791 if (eidx == n) {
3792 break;
3793 }
3794 }
3795
3796 return i <= (size_t)qfl->qf_count ? i : 1;
3797}
3798
3799/*
3800 * ":cc", ":crewind", ":cfirst" and ":clast".
3801 * ":ll", ":lrewind", ":lfirst" and ":llast".
3802 * ":cdo", ":ldo", ":cfdo" and ":lfdo".
3803 */
3804void ex_cc(exarg_T *eap)
3805{
3806 qf_info_T *qi = &ql_info;
3807
3808 if (eap->cmdidx == CMD_ll
3809 || eap->cmdidx == CMD_lrewind
3810 || eap->cmdidx == CMD_lfirst
3811 || eap->cmdidx == CMD_llast
3812 || eap->cmdidx == CMD_ldo
3813 || eap->cmdidx == CMD_lfdo) {
3814 qi = GET_LOC_LIST(curwin);
3815 if (qi == NULL) {
3816 EMSG(_(e_loclist));
3817 return;
3818 }
3819 }
3820
3821 int errornr;
3822 if (eap->addr_count > 0) {
3823 errornr = (int)eap->line2;
3824 } else if (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll) {
3825 errornr = 0;
3826 } else if (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind
3827 || eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst) {
3828 errornr = 1;
3829 } else {
3830 errornr = 32767;
3831 }
3832
3833 // For cdo and ldo commands, jump to the nth valid error.
3834 // For cfdo and lfdo commands, jump to the nth valid file entry.
3835 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
3836 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
3837 size_t n;
3838 if (eap->addr_count > 0) {
3839 assert(eap->line1 >= 0);
3840 n = (size_t)eap->line1;
3841 } else {
3842 n = 1;
3843 }
3844 size_t valid_entry = qf_get_nth_valid_entry(qi, n,
3845 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo);
3846 assert(valid_entry <= INT_MAX);
3847 errornr = (int)valid_entry;
3848 }
3849
3850 qf_jump(qi, 0, errornr, eap->forceit);
3851}
3852
3853/*
3854 * ":cnext", ":cnfile", ":cNext" and ":cprevious".
3855 * ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile".
3856 * ":cdo", ":ldo", ":cfdo" and ":lfdo".
3857 */
3858void ex_cnext(exarg_T *eap)
3859{
3860 qf_info_T *qi = &ql_info;
3861
3862 if (eap->cmdidx == CMD_lnext
3863 || eap->cmdidx == CMD_lNext
3864 || eap->cmdidx == CMD_lprevious
3865 || eap->cmdidx == CMD_lnfile
3866 || eap->cmdidx == CMD_lNfile
3867 || eap->cmdidx == CMD_lpfile
3868 || eap->cmdidx == CMD_ldo
3869 || eap->cmdidx == CMD_lfdo) {
3870 qi = GET_LOC_LIST(curwin);
3871 if (qi == NULL) {
3872 EMSG(_(e_loclist));
3873 return;
3874 }
3875 }
3876
3877 int errornr;
3878 if (eap->addr_count > 0
3879 && (eap->cmdidx != CMD_cdo && eap->cmdidx != CMD_ldo
3880 && eap->cmdidx != CMD_cfdo && eap->cmdidx != CMD_lfdo)) {
3881 errornr = (int)eap->line2;
3882 } else {
3883 errornr = 1;
3884 }
3885
3886 qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext
3887 || eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo)
3888 ? FORWARD
3889 : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile
3890 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
3891 ? FORWARD_FILE
3892 : (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_lpfile
3893 || eap->cmdidx == CMD_cNfile || eap->cmdidx == CMD_lNfile)
3894 ? BACKWARD_FILE
3895 : BACKWARD,
3896 errornr, eap->forceit);
3897}
3898
3899/*
3900 * ":cfile"/":cgetfile"/":caddfile" commands.
3901 * ":lfile"/":lgetfile"/":laddfile" commands.
3902 */
3903void ex_cfile(exarg_T *eap)
3904{
3905 win_T *wp = NULL;
3906 qf_info_T *qi = &ql_info;
3907 char_u *au_name = NULL;
3908
3909 switch (eap->cmdidx) {
3910 case CMD_cfile: au_name = (char_u *)"cfile"; break;
3911 case CMD_cgetfile: au_name = (char_u *)"cgetfile"; break;
3912 case CMD_caddfile: au_name = (char_u *)"caddfile"; break;
3913 case CMD_lfile: au_name = (char_u *)"lfile"; break;
3914 case CMD_lgetfile: au_name = (char_u *)"lgetfile"; break;
3915 case CMD_laddfile: au_name = (char_u *)"laddfile"; break;
3916 default: break;
3917 }
3918 if (au_name != NULL)
3919 apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, NULL, FALSE, curbuf);
3920 if (*eap->arg != NUL)
3921 set_string_option_direct((char_u *)"ef", -1, eap->arg, OPT_FREE, 0);
3922
3923 char_u *enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc;
3924
3925 if (eap->cmdidx == CMD_lfile
3926 || eap->cmdidx == CMD_lgetfile
3927 || eap->cmdidx == CMD_laddfile) {
3928 wp = curwin;
3929 }
3930
3931 // This function is used by the :cfile, :cgetfile and :caddfile
3932 // commands.
3933 // :cfile always creates a new quickfix list and jumps to the
3934 // first error.
3935 // :cgetfile creates a new quickfix list but doesn't jump to the
3936 // first error.
3937 // :caddfile adds to an existing quickfix list. If there is no
3938 // quickfix list then a new list is created.
3939 int res = qf_init(wp, p_ef, p_efm, (eap->cmdidx != CMD_caddfile
3940 && eap->cmdidx != CMD_laddfile),
3941 qf_cmdtitle(*eap->cmdlinep), enc);
3942 if (wp != NULL) {
3943 qi = GET_LOC_LIST(wp);
3944 if (qi == NULL) {
3945 return;
3946 }
3947 }
3948 if (res >= 0) {
3949 qf_list_changed(qi, qi->qf_curlist);
3950 }
3951 unsigned save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
3952 if (au_name != NULL) {
3953 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, NULL, false, curbuf);
3954 }
3955 // Jump to the first error for a new list and if autocmds didn't free the
3956 // list.
3957 if (res > 0 && (eap->cmdidx == CMD_cfile || eap->cmdidx == CMD_lfile)
3958 && qflist_valid(wp, save_qfid)) {
3959 // display the first error
3960 qf_jump_first(qi, save_qfid, eap->forceit);
3961 }
3962}
3963
3964/// Return the vimgrep autocmd name.
3965static char_u *vgr_get_auname(cmdidx_T cmdidx)
3966{
3967 switch (cmdidx) {
3968 case CMD_vimgrep: return (char_u *)"vimgrep";
3969 case CMD_lvimgrep: return (char_u *)"lvimgrep";
3970 case CMD_vimgrepadd: return (char_u *)"vimgrepadd";
3971 case CMD_lvimgrepadd: return (char_u *)"lvimgrepadd";
3972 case CMD_grep: return (char_u *)"grep";
3973 case CMD_lgrep: return (char_u *)"lgrep";
3974 case CMD_grepadd: return (char_u *)"grepadd";
3975 case CMD_lgrepadd: return (char_u *)"lgrepadd";
3976 default: return NULL;
3977 }
3978}
3979
3980/// Initialize the regmatch used by vimgrep for pattern "s".
3981static void vgr_init_regmatch(regmmatch_T *regmatch, char_u *s)
3982{
3983 // Get the search pattern: either white-separated or enclosed in //.
3984 regmatch->regprog = NULL;
3985
3986 if (s == NULL || *s == NUL) {
3987 // Pattern is empty, use last search pattern.
3988 if (last_search_pat() == NULL) {
3989 EMSG(_(e_noprevre));
3990 return;
3991 }
3992 regmatch->regprog = vim_regcomp(last_search_pat(), RE_MAGIC);
3993 } else {
3994 regmatch->regprog = vim_regcomp(s, RE_MAGIC);
3995 }
3996
3997 regmatch->rmm_ic = p_ic;
3998 regmatch->rmm_maxcol = 0;
3999}
4000
4001
4002/// Display a file name when vimgrep is running.
4003static void vgr_display_fname(char_u *fname)
4004{
4005 msg_start();
4006 char_u *p = msg_strtrunc(fname, true);
4007 if (p == NULL) {
4008 msg_outtrans(fname);
4009 } else {
4010 msg_outtrans(p);
4011 xfree(p);
4012 }
4013 msg_clr_eos();
4014 msg_didout = false; // overwrite this message
4015 msg_nowait = true; // don't wait for this message
4016 msg_col = 0;
4017 ui_flush();
4018}
4019
4020/// Load a dummy buffer to search for a pattern using vimgrep.
4021static buf_T *vgr_load_dummy_buf(char_u *fname, char_u *dirname_start,
4022 char_u *dirname_now)
4023{
4024 char_u *save_ei = NULL;
4025
4026 // Don't do Filetype autocommands to avoid loading syntax and
4027 // indent scripts, a great speed improvement.
4028 long save_mls = p_mls;
4029 p_mls = 0;
4030
4031 // Load file into a buffer, so that 'fileencoding' is detected,
4032 // autocommands applied, etc.
4033 buf_T *buf = load_dummy_buffer(fname, dirname_start, dirname_now);
4034
4035 p_mls = save_mls;
4036 au_event_restore(save_ei);
4037
4038 return buf;
4039}
4040
4041/// Check whether a quickfix/location list is valid. Autocmds may remove or
4042/// change a quickfix list when vimgrep is running. If the list is not found,
4043/// create a new list.
4044static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid,
4045 char_u *title)
4046{
4047 // Verify that the quickfix/location list was not freed by an autocmd
4048 if (!qflist_valid(wp, qfid)) {
4049 if (wp != NULL) {
4050 // An autocmd has freed the location list
4051 EMSG(_(e_loc_list_changed));
4052 return false;
4053 } else {
4054 // Quickfix list is not found, create a new one.
4055 qf_new_list(qi, title);
4056 return true;
4057 }
4058 }
4059 if (qf_restore_list(qi, qfid) == FAIL) {
4060 return false;
4061 }
4062
4063 return true;
4064}
4065
4066
4067/// Search for a pattern in all the lines in a buffer and add the matching lines
4068/// to a quickfix list.
4069static bool vgr_match_buflines(qf_info_T *qi, char_u *fname, buf_T *buf,
4070 regmmatch_T *regmatch, long tomatch,
4071 int duplicate_name, int flags)
4072{
4073 bool found_match = false;
4074
4075 for (long lnum = 1; lnum <= buf->b_ml.ml_line_count && tomatch > 0; lnum++) {
4076 colnr_T col = 0;
4077 while (vim_regexec_multi(regmatch, curwin, buf, lnum, col, NULL,
4078 NULL) > 0) {
4079 // Pass the buffer number so that it gets used even for a
4080 // dummy buffer, unless duplicate_name is set, then the
4081 // buffer will be wiped out below.
4082 if (qf_add_entry(qi,
4083 qi->qf_curlist,
4084 NULL, // dir
4085 fname,
4086 NULL,
4087 duplicate_name ? 0 : buf->b_fnum,
4088 ml_get_buf(buf, regmatch->startpos[0].lnum + lnum,
4089 false),
4090 regmatch->startpos[0].lnum + lnum,
4091 regmatch->startpos[0].col + 1,
4092 false, // vis_col
4093 NULL, // search pattern
4094 0, // nr
4095 0, // type
4096 true // valid
4097 ) == FAIL) {
4098 got_int = true;
4099 break;
4100 }
4101 found_match = true;
4102 if (--tomatch == 0) {
4103 break;
4104 }
4105 if ((flags & VGR_GLOBAL) == 0 || regmatch->endpos[0].lnum > 0) {
4106 break;
4107 }
4108 col = regmatch->endpos[0].col + (col == regmatch->endpos[0].col);
4109 if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, false))) {
4110 break;
4111 }
4112 }
4113 line_breakcheck();
4114 if (got_int) {
4115 break;
4116 }
4117 }
4118
4119 return found_match;
4120}
4121
4122/// Jump to the first match and update the directory.
4123static void vgr_jump_to_match(qf_info_T *qi, int forceit, int *redraw_for_dummy,
4124 buf_T *first_match_buf, char_u *target_dir)
4125{
4126 buf_T *buf = curbuf;
4127 qf_jump(qi, 0, 0, forceit);
4128 if (buf != curbuf) {
4129 // If we jumped to another buffer redrawing will already be
4130 // taken care of.
4131 *redraw_for_dummy = false;
4132 }
4133
4134 // Jump to the directory used after loading the buffer.
4135 if (curbuf == first_match_buf && target_dir != NULL) {
4136 exarg_T ea = {
4137 .arg = target_dir,
4138 .cmdidx = CMD_lcd,
4139 };
4140 ex_cd(&ea);
4141 }
4142}
4143
4144/*
4145 * ":vimgrep {pattern} file(s)"
4146 * ":vimgrepadd {pattern} file(s)"
4147 * ":lvimgrep {pattern} file(s)"
4148 * ":lvimgrepadd {pattern} file(s)"
4149 */
4150void ex_vimgrep(exarg_T *eap)
4151{
4152 regmmatch_T regmatch;
4153 int fcount;
4154 char_u **fnames;
4155 char_u *fname;
4156 char_u *s;
4157 char_u *p;
4158 int fi;
4159 qf_info_T *qi = &ql_info;
4160 win_T *wp = NULL;
4161 buf_T *buf;
4162 int duplicate_name = FALSE;
4163 int using_dummy;
4164 int redraw_for_dummy = FALSE;
4165 int found_match;
4166 buf_T *first_match_buf = NULL;
4167 time_t seconds = 0;
4168 aco_save_T aco;
4169 int flags = 0;
4170 long tomatch;
4171 char_u *dirname_start = NULL;
4172 char_u *dirname_now = NULL;
4173 char_u *target_dir = NULL;
4174 char_u *au_name = NULL;
4175
4176 au_name = vgr_get_auname(eap->cmdidx);
4177 if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
4178 curbuf->b_fname, true, curbuf)) {
4179 if (aborting()) {
4180 return;
4181 }
4182 }
4183
4184 if (eap->cmdidx == CMD_lgrep
4185 || eap->cmdidx == CMD_lvimgrep
4186 || eap->cmdidx == CMD_lgrepadd
4187 || eap->cmdidx == CMD_lvimgrepadd) {
4188 qi = ll_get_or_alloc_list(curwin);
4189 wp = curwin;
4190 }
4191
4192 if (eap->addr_count > 0)
4193 tomatch = eap->line2;
4194 else
4195 tomatch = MAXLNUM;
4196
4197 /* Get the search pattern: either white-separated or enclosed in // */
4198 regmatch.regprog = NULL;
4199 char_u *title = vim_strsave(qf_cmdtitle(*eap->cmdlinep));
4200 p = skip_vimgrep_pat(eap->arg, &s, &flags);
4201 if (p == NULL) {
4202 EMSG(_(e_invalpat));
4203 goto theend;
4204 }
4205
4206 vgr_init_regmatch(&regmatch, s);
4207 if (regmatch.regprog == NULL) {
4208 goto theend;
4209 }
4210
4211 p = skipwhite(p);
4212 if (*p == NUL) {
4213 EMSG(_("E683: File name missing or invalid pattern"));
4214 goto theend;
4215 }
4216
4217 if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd
4218 && eap->cmdidx != CMD_vimgrepadd && eap->cmdidx != CMD_lvimgrepadd)
4219 || qi->qf_curlist == qi->qf_listcount) {
4220 // make place for a new list
4221 qf_new_list(qi, title);
4222 }
4223
4224 /* parse the list of arguments */
4225 if (get_arglist_exp(p, &fcount, &fnames, true) == FAIL)
4226 goto theend;
4227 if (fcount == 0) {
4228 EMSG(_(e_nomatch));
4229 goto theend;
4230 }
4231
4232 dirname_start = xmalloc(MAXPATHL);
4233 dirname_now = xmalloc(MAXPATHL);
4234
4235 /* Remember the current directory, because a BufRead autocommand that does
4236 * ":lcd %:p:h" changes the meaning of short path names. */
4237 os_dirname(dirname_start, MAXPATHL);
4238
4239 // Remember the current quickfix list identifier, so that we can check for
4240 // autocommands changing the current quickfix list.
4241 unsigned save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
4242
4243 seconds = (time_t)0;
4244 for (fi = 0; fi < fcount && !got_int && tomatch > 0; fi++) {
4245 fname = path_try_shorten_fname(fnames[fi]);
4246 if (time(NULL) > seconds) {
4247 /* Display the file name every second or so, show the user we are
4248 * working on it. */
4249 seconds = time(NULL);
4250 vgr_display_fname(fname);
4251 }
4252
4253 buf = buflist_findname_exp(fnames[fi]);
4254 if (buf == NULL || buf->b_ml.ml_mfp == NULL) {
4255 /* Remember that a buffer with this name already exists. */
4256 duplicate_name = (buf != NULL);
4257 using_dummy = TRUE;
4258 redraw_for_dummy = TRUE;
4259
4260 buf = vgr_load_dummy_buf(fname, dirname_start, dirname_now);
4261 } else {
4262 // Use existing, loaded buffer.
4263 using_dummy = false;
4264 }
4265
4266 // Check whether the quickfix list is still valid. When loading a
4267 // buffer above, autocommands might have changed the quickfix list.
4268 if (!vgr_qflist_valid(wp, qi, save_qfid, *eap->cmdlinep)) {
4269 FreeWild(fcount, fnames);
4270 goto theend;
4271 }
4272 save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
4273
4274 if (buf == NULL) {
4275 if (!got_int)
4276 smsg(_("Cannot open file \"%s\""), fname);
4277 } else {
4278 // Try for a match in all lines of the buffer.
4279 // For ":1vimgrep" look for first match only.
4280 found_match = vgr_match_buflines(qi, fname, buf, &regmatch, tomatch,
4281 duplicate_name, flags);
4282
4283 if (using_dummy) {
4284 if (found_match && first_match_buf == NULL)
4285 first_match_buf = buf;
4286 if (duplicate_name) {
4287 /* Never keep a dummy buffer if there is another buffer
4288 * with the same name. */
4289 wipe_dummy_buffer(buf, dirname_start);
4290 buf = NULL;
4291 } else if (!cmdmod.hide
4292 || buf->b_p_bh[0] == 'u' /* "unload" */
4293 || buf->b_p_bh[0] == 'w' /* "wipe" */
4294 || buf->b_p_bh[0] == 'd') { /* "delete" */
4295 /* When no match was found we don't need to remember the
4296 * buffer, wipe it out. If there was a match and it
4297 * wasn't the first one or we won't jump there: only
4298 * unload the buffer.
4299 * Ignore 'hidden' here, because it may lead to having too
4300 * many swap files. */
4301 if (!found_match) {
4302 wipe_dummy_buffer(buf, dirname_start);
4303 buf = NULL;
4304 } else if (buf != first_match_buf || (flags & VGR_NOJUMP)) {
4305 unload_dummy_buffer(buf, dirname_start);
4306 // Keeping the buffer, remove the dummy flag.
4307 buf->b_flags &= ~BF_DUMMY;
4308 buf = NULL;
4309 }
4310 }
4311
4312 if (buf != NULL) {
4313 // Keeping the buffer, remove the dummy flag.
4314 buf->b_flags &= ~BF_DUMMY;
4315
4316 // If the buffer is still loaded we need to use the
4317 // directory we jumped to below.
4318 if (buf == first_match_buf
4319 && target_dir == NULL
4320 && STRCMP(dirname_start, dirname_now) != 0) {
4321 target_dir = vim_strsave(dirname_now);
4322 }
4323
4324 /* The buffer is still loaded, the Filetype autocommands
4325 * need to be done now, in that buffer. And the modelines
4326 * need to be done (again). But not the window-local
4327 * options! */
4328 aucmd_prepbuf(&aco, buf);
4329 apply_autocmds(EVENT_FILETYPE, buf->b_p_ft,
4330 buf->b_fname, TRUE, buf);
4331 do_modelines(OPT_NOWIN);
4332 aucmd_restbuf(&aco);
4333 }
4334 }
4335 }
4336 }
4337
4338 FreeWild(fcount, fnames);
4339
4340 qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE;
4341 qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start;
4342 qi->qf_lists[qi->qf_curlist].qf_index = 1;
4343 qf_list_changed(qi, qi->qf_curlist);
4344
4345 qf_update_buffer(qi, NULL);
4346
4347 if (au_name != NULL)
4348 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
4349 curbuf->b_fname, TRUE, curbuf);
4350
4351 // The QuickFixCmdPost autocmd may free the quickfix list. Check the list
4352 // is still valid.
4353 if (!qflist_valid(wp, save_qfid)) {
4354 goto theend;
4355 }
4356
4357 if (qf_restore_list(qi, save_qfid) == FAIL) {
4358 goto theend;
4359 }
4360
4361 /* Jump to first match. */
4362 if (qi->qf_lists[qi->qf_curlist].qf_count > 0) {
4363 if ((flags & VGR_NOJUMP) == 0) {
4364 vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy, first_match_buf,
4365 target_dir);
4366 }
4367 } else
4368 EMSG2(_(e_nomatch2), s);
4369
4370 /* If we loaded a dummy buffer into the current window, the autocommands
4371 * may have messed up things, need to redraw and recompute folds. */
4372 if (redraw_for_dummy) {
4373 foldUpdateAll(curwin);
4374 }
4375
4376theend:
4377 xfree(title);
4378 xfree(dirname_now);
4379 xfree(dirname_start);
4380 xfree(target_dir);
4381 vim_regfree(regmatch.regprog);
4382}
4383
4384/*
4385 * Restore current working directory to "dirname_start" if they differ, taking
4386 * into account whether it is set locally or globally.
4387 */
4388static void restore_start_dir(char_u *dirname_start)
4389{
4390 char_u *dirname_now = xmalloc(MAXPATHL);
4391
4392 os_dirname(dirname_now, MAXPATHL);
4393 if (STRCMP(dirname_start, dirname_now) != 0) {
4394 /* If the directory has changed, change it back by building up an
4395 * appropriate ex command and executing it. */
4396 exarg_T ea = {
4397 .arg = dirname_start,
4398 .cmdidx = (curwin->w_localdir == NULL) ? CMD_cd : CMD_lcd,
4399 };
4400 ex_cd(&ea);
4401 }
4402 xfree(dirname_now);
4403}
4404
4405/*
4406 * Load file "fname" into a dummy buffer and return the buffer pointer,
4407 * placing the directory resulting from the buffer load into the
4408 * "resulting_dir" pointer. "resulting_dir" must be allocated by the caller
4409 * prior to calling this function. Restores directory to "dirname_start" prior
4410 * to returning, if autocmds or the 'autochdir' option have changed it.
4411 *
4412 * If creating the dummy buffer does not fail, must call unload_dummy_buffer()
4413 * or wipe_dummy_buffer() later!
4414 *
4415 * Returns NULL if it fails.
4416 */
4417static buf_T *
4418load_dummy_buffer (
4419 char_u *fname,
4420 char_u *dirname_start, /* in: old directory */
4421 char_u *resulting_dir /* out: new directory */
4422)
4423{
4424 buf_T *newbuf;
4425 bufref_T newbufref;
4426 bufref_T newbuf_to_wipe;
4427 int failed = true;
4428 aco_save_T aco;
4429 int readfile_result;
4430
4431 // Allocate a buffer without putting it in the buffer list.
4432 newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
4433 if (newbuf == NULL) {
4434 return NULL;
4435 }
4436 set_bufref(&newbufref, newbuf);
4437
4438 /* Init the options. */
4439 buf_copy_options(newbuf, BCO_ENTER | BCO_NOHELP);
4440
4441 /* need to open the memfile before putting the buffer in a window */
4442 if (ml_open(newbuf) == OK) {
4443 // Make sure this buffer isn't wiped out by autocommands.
4444 newbuf->b_locked++;
4445 // set curwin/curbuf to buf and save a few things
4446 aucmd_prepbuf(&aco, newbuf);
4447
4448 /* Need to set the filename for autocommands. */
4449 (void)setfname(curbuf, fname, NULL, FALSE);
4450
4451 /* Create swap file now to avoid the ATTENTION message. */
4452 check_need_swap(TRUE);
4453
4454 /* Remove the "dummy" flag, otherwise autocommands may not
4455 * work. */
4456 curbuf->b_flags &= ~BF_DUMMY;
4457
4458 newbuf_to_wipe.br_buf = NULL;
4459 readfile_result = readfile(fname, NULL, (linenr_T)0, (linenr_T)0,
4460 (linenr_T)MAXLNUM, NULL,
4461 READ_NEW | READ_DUMMY);
4462 newbuf->b_locked--;
4463 if (readfile_result == OK
4464 && !got_int
4465 && !(curbuf->b_flags & BF_NEW)) {
4466 failed = FALSE;
4467 if (curbuf != newbuf) {
4468 // Bloody autocommands changed the buffer! Can happen when
4469 // using netrw and editing a remote file. Use the current
4470 // buffer instead, delete the dummy one after restoring the
4471 // window stuff.
4472 set_bufref(&newbuf_to_wipe, newbuf);
4473 newbuf = curbuf;
4474 }
4475 }
4476
4477 // Restore curwin/curbuf and a few other things.
4478 aucmd_restbuf(&aco);
4479 if (newbuf_to_wipe.br_buf != NULL && bufref_valid(&newbuf_to_wipe)) {
4480 wipe_buffer(newbuf_to_wipe.br_buf, false);
4481 }
4482
4483 // Add back the "dummy" flag, otherwise buflist_findname_file_id()
4484 // won't skip it.
4485 newbuf->b_flags |= BF_DUMMY;
4486 }
4487
4488 /*
4489 * When autocommands/'autochdir' option changed directory: go back.
4490 * Let the caller know what the resulting dir was first, in case it is
4491 * important.
4492 */
4493 os_dirname(resulting_dir, MAXPATHL);
4494 restore_start_dir(dirname_start);
4495
4496 if (!bufref_valid(&newbufref)) {
4497 return NULL;
4498 }
4499 if (failed) {
4500 wipe_dummy_buffer(newbuf, dirname_start);
4501 return NULL;
4502 }
4503 return newbuf;
4504}
4505
4506/*
4507 * Wipe out the dummy buffer that load_dummy_buffer() created. Restores
4508 * directory to "dirname_start" prior to returning, if autocmds or the
4509 * 'autochdir' option have changed it.
4510 */
4511static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start)
4512{
4513 if (curbuf != buf) { /* safety check */
4514 cleanup_T cs;
4515
4516 /* Reset the error/interrupt/exception state here so that aborting()
4517 * returns FALSE when wiping out the buffer. Otherwise it doesn't
4518 * work when got_int is set. */
4519 enter_cleanup(&cs);
4520
4521 wipe_buffer(buf, FALSE);
4522
4523 /* Restore the error/interrupt/exception state if not discarded by a
4524 * new aborting error, interrupt, or uncaught exception. */
4525 leave_cleanup(&cs);
4526 /* When autocommands/'autochdir' option changed directory: go back. */
4527 restore_start_dir(dirname_start);
4528 }
4529}
4530
4531/*
4532 * Unload the dummy buffer that load_dummy_buffer() created. Restores
4533 * directory to "dirname_start" prior to returning, if autocmds or the
4534 * 'autochdir' option have changed it.
4535 */
4536static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start)
4537{
4538 if (curbuf != buf) { /* safety check */
4539 close_buffer(NULL, buf, DOBUF_UNLOAD, FALSE);
4540
4541 /* When autocommands/'autochdir' option changed directory: go back. */
4542 restore_start_dir(dirname_start);
4543 }
4544}
4545
4546/// Add each quickfix error to list "list" as a dictionary.
4547/// If qf_idx is -1, use the current list. Otherwise, use the specified list.
4548int get_errorlist(const qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list)
4549{
4550 const qf_info_T *qi = qi_arg;
4551 char_u buf[2];
4552 qfline_T *qfp;
4553 int i;
4554 int bufnum;
4555
4556 if (qi == NULL) {
4557 qi = &ql_info;
4558 if (wp != NULL) {
4559 qi = GET_LOC_LIST(wp);
4560 if (qi == NULL) {
4561 return FAIL;
4562 }
4563 }
4564 }
4565
4566 if (qf_idx == INVALID_QFIDX) {
4567 qf_idx = qi->qf_curlist;
4568 }
4569
4570 if (qf_idx >= qi->qf_listcount
4571 || qi->qf_lists[qf_idx].qf_count == 0) {
4572 return FAIL;
4573 }
4574
4575 qfp = qi->qf_lists[qf_idx].qf_start;
4576 for (i = 1; !got_int && i <= qi->qf_lists[qf_idx].qf_count; i++) {
4577 // Handle entries with a non-existing buffer number.
4578 bufnum = qfp->qf_fnum;
4579 if (bufnum != 0 && (buflist_findnr(bufnum) == NULL))
4580 bufnum = 0;
4581
4582 dict_T *const dict = tv_dict_alloc();
4583 tv_list_append_dict(list, dict);
4584
4585 buf[0] = qfp->qf_type;
4586 buf[1] = NUL;
4587 if (tv_dict_add_nr(dict, S_LEN("bufnr"), (varnumber_T)bufnum) == FAIL
4588 || (tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)qfp->qf_lnum)
4589 == FAIL)
4590 || (tv_dict_add_nr(dict, S_LEN("col"), (varnumber_T)qfp->qf_col)
4591 == FAIL)
4592 || (tv_dict_add_nr(dict, S_LEN("vcol"), (varnumber_T)qfp->qf_viscol)
4593 == FAIL)
4594 || (tv_dict_add_nr(dict, S_LEN("nr"), (varnumber_T)qfp->qf_nr) == FAIL)
4595 || tv_dict_add_str(dict, S_LEN("module"),
4596 (qfp->qf_module == NULL
4597 ? ""
4598 : (const char *)qfp->qf_module)) == FAIL
4599 || tv_dict_add_str(dict, S_LEN("pattern"),
4600 (qfp->qf_pattern == NULL
4601 ? ""
4602 : (const char *)qfp->qf_pattern)) == FAIL
4603 || tv_dict_add_str(dict, S_LEN("text"),
4604 (qfp->qf_text == NULL
4605 ? ""
4606 : (const char *)qfp->qf_text)) == FAIL
4607 || tv_dict_add_str(dict, S_LEN("type"), (const char *)buf) == FAIL
4608 || (tv_dict_add_nr(dict, S_LEN("valid"), (varnumber_T)qfp->qf_valid)
4609 == FAIL)) {
4610 // tv_dict_add* fail only if key already exist, but this is a newly
4611 // allocated dictionary which is thus guaranteed to have no existing keys.
4612 assert(false);
4613 }
4614
4615 qfp = qfp->qf_next;
4616 if (qfp == NULL) {
4617 break;
4618 }
4619 }
4620 return OK;
4621}
4622
4623/// Flags used by getqflist()/getloclist() to determine which fields to return.
4624enum {
4625 QF_GETLIST_NONE = 0x0,
4626 QF_GETLIST_TITLE = 0x1,
4627 QF_GETLIST_ITEMS = 0x2,
4628 QF_GETLIST_NR = 0x4,
4629 QF_GETLIST_WINID = 0x8,
4630 QF_GETLIST_CONTEXT = 0x10,
4631 QF_GETLIST_ID = 0x20,
4632 QF_GETLIST_IDX = 0x40,
4633 QF_GETLIST_SIZE = 0x80,
4634 QF_GETLIST_TICK = 0x100,
4635 QF_GETLIST_ALL = 0x1FF
4636};
4637
4638/// Parse text from 'di' and return the quickfix list items.
4639/// Existing quickfix lists are not modified.
4640static int qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict)
4641{
4642 int status = FAIL;
4643 char_u *errorformat = p_efm;
4644 dictitem_T *efm_di;
4645
4646 // Only a List value is supported
4647 if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) {
4648 // If errorformat is supplied then use it, otherwise use the 'efm'
4649 // option setting
4650 if ((efm_di = tv_dict_find(what, S_LEN("efm"))) != NULL) {
4651 if (efm_di->di_tv.v_type != VAR_STRING
4652 || efm_di->di_tv.vval.v_string == NULL) {
4653 return FAIL;
4654 }
4655 errorformat = efm_di->di_tv.vval.v_string;
4656 }
4657
4658 list_T *l = tv_list_alloc(kListLenMayKnow);
4659 qf_info_T *const qi = ll_new_list();
4660
4661 if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat,
4662 true, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) {
4663 (void)get_errorlist(qi, NULL, 0, l);
4664 qf_free(qi, 0);
4665 }
4666 xfree(qi);
4667
4668 tv_dict_add_list(retdict, S_LEN("items"), l);
4669 status = OK;
4670 }
4671
4672 return status;
4673}
4674
4675/// Return the quickfix/location list window identifier in the current tabpage.
4676static int qf_winid(qf_info_T *qi)
4677{
4678 // The quickfix window can be opened even if the quickfix list is not set
4679 // using ":copen". This is not true for location lists.
4680 if (qi == NULL) {
4681 return 0;
4682 }
4683 win_T *win = qf_find_win(qi);
4684 if (win != NULL) {
4685 return win->handle;
4686 }
4687 return 0;
4688}
4689
4690/// Convert the keys in 'what' to quickfix list property flags.
4691static int qf_getprop_keys2flags(dict_T *what)
4692{
4693 int flags = QF_GETLIST_NONE;
4694
4695 if (tv_dict_find(what, S_LEN("all")) != NULL) {
4696 flags |= QF_GETLIST_ALL;
4697 }
4698 if (tv_dict_find(what, S_LEN("title")) != NULL) {
4699 flags |= QF_GETLIST_TITLE;
4700 }
4701 if (tv_dict_find(what, S_LEN("nr")) != NULL) {
4702 flags |= QF_GETLIST_NR;
4703 }
4704 if (tv_dict_find(what, S_LEN("winid")) != NULL) {
4705 flags |= QF_GETLIST_WINID;
4706 }
4707 if (tv_dict_find(what, S_LEN("context")) != NULL) {
4708 flags |= QF_GETLIST_CONTEXT;
4709 }
4710 if (tv_dict_find(what, S_LEN("id")) != NULL) {
4711 flags |= QF_GETLIST_ID;
4712 }
4713 if (tv_dict_find(what, S_LEN("items")) != NULL) {
4714 flags |= QF_GETLIST_ITEMS;
4715 }
4716 if (tv_dict_find(what, S_LEN("idx")) != NULL) {
4717 flags |= QF_GETLIST_IDX;
4718 }
4719 if (tv_dict_find(what, S_LEN("size")) != NULL) {
4720 flags |= QF_GETLIST_SIZE;
4721 }
4722 if (tv_dict_find(what, S_LEN("changedtick")) != NULL) {
4723 flags |= QF_GETLIST_TICK;
4724 }
4725
4726 return flags;
4727}
4728
4729/// Return the quickfix list index based on 'nr' or 'id' in 'what'.
4730///
4731/// If 'nr' and 'id' are not present in 'what' then return the current
4732/// quickfix list index.
4733/// If 'nr' is zero then return the current quickfix list index.
4734/// If 'nr' is '$' then return the last quickfix list index.
4735/// If 'id' is present then return the index of the quickfix list with that id.
4736/// If 'id' is zero then return the quickfix list index specified by 'nr'.
4737/// Return -1, if quickfix list is not present or if the stack is empty.
4738static int qf_getprop_qfidx(qf_info_T *qi, dict_T *what)
4739{
4740 dictitem_T *di = NULL;
4741
4742 int qf_idx = qi->qf_curlist; // default is the current list
4743 if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) {
4744 // Use the specified quickfix/location list
4745 if (di->di_tv.v_type == VAR_NUMBER) {
4746 // for zero use the current list
4747 if (di->di_tv.vval.v_number != 0) {
4748 qf_idx = (int)di->di_tv.vval.v_number - 1;
4749 if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
4750 qf_idx = INVALID_QFIDX;
4751 }
4752 }
4753 } else if (di->di_tv.v_type == VAR_STRING
4754 && strequal((const char *)di->di_tv.vval.v_string, "$")) {
4755 // Get the last quickfix list number
4756 qf_idx = qi->qf_listcount - 1;
4757 } else {
4758 qf_idx = INVALID_QFIDX;
4759 }
4760 }
4761
4762 if ((di = tv_dict_find(what, S_LEN("id"))) != NULL) {
4763 // Look for a list with the specified id
4764 if (di->di_tv.v_type == VAR_NUMBER) {
4765 // For zero, use the current list or the list specifed by 'nr'
4766 if (di->di_tv.vval.v_number != 0) {
4767 qf_idx = qf_id2nr(qi, (unsigned)di->di_tv.vval.v_number);
4768 }
4769 } else {
4770 qf_idx = INVALID_QFIDX;
4771 }
4772 }
4773
4774 return qf_idx;
4775}
4776
4777/// Return default values for quickfix list properties in retdict.
4778static int qf_getprop_defaults(qf_info_T *qi, int flags, dict_T *retdict)
4779{
4780 int status = OK;
4781
4782 if (flags & QF_GETLIST_TITLE) {
4783 status = tv_dict_add_str(retdict, S_LEN("title"), (const char *)"");
4784 }
4785 if ((status == OK) && (flags & QF_GETLIST_ITEMS)) {
4786 list_T *l = tv_list_alloc(kListLenMayKnow);
4787 status = tv_dict_add_list(retdict, S_LEN("items"), l);
4788 }
4789 if ((status == OK) && (flags & QF_GETLIST_NR)) {
4790 status = tv_dict_add_nr(retdict, S_LEN("nr"), 0);
4791 }
4792 if ((status == OK) && (flags & QF_GETLIST_WINID)) {
4793 status = tv_dict_add_nr(retdict, S_LEN("winid"), qf_winid(qi));
4794 }
4795 if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) {
4796 status = tv_dict_add_str(retdict, S_LEN("context"), (const char *)"");
4797 }
4798 if ((status == OK) && (flags & QF_GETLIST_ID)) {
4799 status = tv_dict_add_nr(retdict, S_LEN("id"), 0);
4800 }
4801 if ((status == OK) && (flags & QF_GETLIST_IDX)) {
4802 status = tv_dict_add_nr(retdict, S_LEN("idx"), 0);
4803 }
4804 if ((status == OK) && (flags & QF_GETLIST_SIZE)) {
4805 status = tv_dict_add_nr(retdict, S_LEN("size"), 0);
4806 }
4807 if ((status == OK) && (flags & QF_GETLIST_TICK)) {
4808 status = tv_dict_add_nr(retdict, S_LEN("changedtick"), 0);
4809 }
4810
4811 return status;
4812}
4813
4814/// Return the quickfix list title as 'title' in retdict
4815static int qf_getprop_title(qf_info_T *qi, int qf_idx, dict_T *retdict)
4816{
4817 return tv_dict_add_str(retdict, S_LEN("title"),
4818 (const char *)qi->qf_lists[qf_idx].qf_title);
4819}
4820
4821/// Return the quickfix list items/entries as 'items' in retdict
4822static int qf_getprop_items(qf_info_T *qi, int qf_idx, dict_T *retdict)
4823{
4824 list_T *l = tv_list_alloc(kListLenMayKnow);
4825 get_errorlist(qi, NULL, qf_idx, l);
4826 tv_dict_add_list(retdict, S_LEN("items"), l);
4827
4828 return OK;
4829}
4830
4831/// Return the quickfix list context (if any) as 'context' in retdict.
4832static int qf_getprop_ctx(qf_info_T *qi, int qf_idx, dict_T *retdict)
4833{
4834 int status;
4835
4836 if (qi->qf_lists[qf_idx].qf_ctx != NULL) {
4837 dictitem_T *di = tv_dict_item_alloc_len(S_LEN("context"));
4838 tv_copy(qi->qf_lists[qf_idx].qf_ctx, &di->di_tv);
4839 status = tv_dict_add(retdict, di);
4840 if (status == FAIL) {
4841 tv_dict_item_free(di);
4842 }
4843 } else {
4844 status = tv_dict_add_str(retdict, S_LEN("context"), "");
4845 }
4846
4847 return status;
4848}
4849
4850/// Return the quickfix list index as 'idx' in retdict
4851static int qf_getprop_idx(qf_info_T *qi, int qf_idx, dict_T *retdict)
4852{
4853 int idx = qi->qf_lists[qf_idx].qf_index;
4854 if (qi->qf_lists[qf_idx].qf_count == 0) {
4855 // For empty lists, qf_index is set to 1
4856 idx = 0;
4857 }
4858 return tv_dict_add_nr(retdict, S_LEN("idx"), idx);
4859}
4860
4861/// Return quickfix/location list details (title) as a dictionary.
4862/// 'what' contains the details to return. If 'list_idx' is -1,
4863/// then current list is used. Otherwise the specified list is used.
4864int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
4865{
4866 qf_info_T *qi = &ql_info;
4867 dictitem_T *di = NULL;
4868 int status = OK;
4869 int qf_idx;
4870
4871 if ((di = tv_dict_find(what, S_LEN("lines"))) != NULL) {
4872 return qf_get_list_from_lines(what, di, retdict);
4873 }
4874
4875 if (wp != NULL) {
4876 qi = GET_LOC_LIST(wp);
4877 }
4878
4879 int flags = qf_getprop_keys2flags(what);
4880
4881 if (qi != NULL && qi->qf_listcount != 0) {
4882 qf_idx = qf_getprop_qfidx(qi, what);
4883 }
4884
4885 // List is not present or is empty
4886 if (qi == NULL || qi->qf_listcount == 0 || qf_idx == INVALID_QFIDX) {
4887 return qf_getprop_defaults(qi, flags, retdict);
4888 }
4889
4890 if (flags & QF_GETLIST_TITLE) {
4891 status = qf_getprop_title(qi, qf_idx, retdict);
4892 }
4893 if ((status == OK) && (flags & QF_GETLIST_NR)) {
4894 status = tv_dict_add_nr(retdict, S_LEN("nr"), qf_idx + 1);
4895 }
4896 if ((status == OK) && (flags & QF_GETLIST_WINID)) {
4897 status = tv_dict_add_nr(retdict, S_LEN("winid"), qf_winid(qi));
4898 }
4899 if ((status == OK) && (flags & QF_GETLIST_ITEMS)) {
4900 status = qf_getprop_items(qi, qf_idx, retdict);
4901 }
4902 if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) {
4903 status = qf_getprop_ctx(qi, qf_idx, retdict);
4904 }
4905 if ((status == OK) && (flags & QF_GETLIST_ID)) {
4906 status = tv_dict_add_nr(retdict, S_LEN("id"), qi->qf_lists[qf_idx].qf_id);
4907 }
4908 if ((status == OK) && (flags & QF_GETLIST_IDX)) {
4909 status = qf_getprop_idx(qi, qf_idx, retdict);
4910 }
4911 if ((status == OK) && (flags & QF_GETLIST_SIZE)) {
4912 status = tv_dict_add_nr(retdict, S_LEN("size"),
4913 qi->qf_lists[qf_idx].qf_count);
4914 }
4915 if ((status == OK) && (flags & QF_GETLIST_TICK)) {
4916 status = tv_dict_add_nr(retdict, S_LEN("changedtick"),
4917 qi->qf_lists[qf_idx].qf_changedtick);
4918 }
4919
4920 return status;
4921}
4922
4923/// Add list of entries to quickfix/location list. Each list entry is
4924/// a dictionary with item information.
4925static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list,
4926 char_u *title, int action)
4927{
4928 dict_T *d;
4929 qfline_T *old_last = NULL;
4930 int retval = OK;
4931 bool did_bufnr_emsg = false;
4932
4933 if (action == ' ' || qf_idx == qi->qf_listcount) {
4934 // make place for a new list
4935 qf_new_list(qi, title);
4936 qf_idx = qi->qf_curlist;
4937 } else if (action == 'a' && qi->qf_lists[qf_idx].qf_count > 0) {
4938 // Adding to existing list, use last entry.
4939 old_last = qi->qf_lists[qf_idx].qf_last;
4940 } else if (action == 'r') {
4941 qf_free_items(qi, qf_idx);
4942 qf_store_title(qi, qf_idx, title);
4943 }
4944
4945 TV_LIST_ITER_CONST(list, li, {
4946 if (TV_LIST_ITEM_TV(li)->v_type != VAR_DICT) {
4947 continue; // Skip non-dict items.
4948 }
4949
4950 d = TV_LIST_ITEM_TV(li)->vval.v_dict;
4951 if (d == NULL) {
4952 continue;
4953 }
4954
4955 char *const filename = tv_dict_get_string(d, "filename", true);
4956 char *const module = tv_dict_get_string(d, "module", true);
4957 int bufnum = (int)tv_dict_get_number(d, "bufnr");
4958 long lnum = (long)tv_dict_get_number(d, "lnum");
4959 int col = (int)tv_dict_get_number(d, "col");
4960 char_u vcol = (char_u)tv_dict_get_number(d, "vcol");
4961 int nr = (int)tv_dict_get_number(d, "nr");
4962 const char *type_str = tv_dict_get_string(d, "type", false);
4963 const char_u type = (char_u)(uint8_t)(type_str == NULL ? NUL : *type_str);
4964 char *const pattern = tv_dict_get_string(d, "pattern", true);
4965 char *text = tv_dict_get_string(d, "text", true);
4966 if (text == NULL) {
4967 text = xcalloc(1, 1);
4968 }
4969 bool valid = true;
4970 if ((filename == NULL && bufnum == 0) || (lnum == 0 && pattern == NULL)) {
4971 valid = false;
4972 }
4973
4974 /* Mark entries with non-existing buffer number as not valid. Give the
4975 * error message only once. */
4976 if (bufnum != 0 && (buflist_findnr(bufnum) == NULL)) {
4977 if (!did_bufnr_emsg) {
4978 did_bufnr_emsg = TRUE;
4979 EMSGN(_("E92: Buffer %" PRId64 " not found"), bufnum);
4980 }
4981 valid = false;
4982 bufnum = 0;
4983 }
4984
4985 // If the 'valid' field is present it overrules the detected value.
4986 if (tv_dict_find(d, "valid", -1) != NULL) {
4987 valid = (int)tv_dict_get_number(d, "valid");
4988 }
4989
4990 int status = qf_add_entry(qi,
4991 qf_idx,
4992 NULL, // dir
4993 (char_u *)filename,
4994 (char_u *)module,
4995 bufnum,
4996 (char_u *)text,
4997 lnum,
4998 col,
4999 vcol, // vis_col
5000 (char_u *)pattern, // search pattern
5001 nr,
5002 type,
5003 valid);
5004
5005 xfree(filename);
5006 xfree(module);
5007 xfree(pattern);
5008 xfree(text);
5009
5010 if (status == FAIL) {
5011 retval = FAIL;
5012 break;
5013 }
5014 });
5015
5016 if (qi->qf_lists[qf_idx].qf_index == 0) {
5017 // no valid entry
5018 qi->qf_lists[qf_idx].qf_nonevalid = true;
5019 } else {
5020 qi->qf_lists[qf_idx].qf_nonevalid = false;
5021 }
5022 if (action != 'a') {
5023 qi->qf_lists[qf_idx].qf_ptr = qi->qf_lists[qf_idx].qf_start;
5024 if (qi->qf_lists[qf_idx].qf_count > 0) {
5025 qi->qf_lists[qf_idx].qf_index = 1;
5026 }
5027 }
5028
5029 // Don't update the cursor in quickfix window when appending entries
5030 qf_update_buffer(qi, old_last);
5031
5032 return retval;
5033}
5034
5035// Get the quickfix list index from 'nr' or 'id'
5036static int qf_setprop_get_qfidx(
5037 const qf_info_T *qi,
5038 const dict_T *what,
5039 int action,
5040 bool *newlist)
5041 FUNC_ATTR_NONNULL_ALL
5042{
5043 dictitem_T *di;
5044 int qf_idx = qi->qf_curlist; // default is the current list
5045
5046 if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) {
5047 // Use the specified quickfix/location list
5048 if (di->di_tv.v_type == VAR_NUMBER) {
5049 // for zero use the current list
5050 if (di->di_tv.vval.v_number != 0) {
5051 qf_idx = (int)di->di_tv.vval.v_number - 1;
5052 }
5053
5054 if ((action == ' ' || action == 'a') && qf_idx == qi->qf_listcount) {
5055 // When creating a new list, accept qf_idx pointing to the next
5056 // non-available list and add the new list at the end of the
5057 // stack.
5058 *newlist = true;
5059 qf_idx = qi->qf_listcount > 0 ? qi->qf_listcount - 1 : 0;
5060 } else if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
5061 return INVALID_QFIDX;
5062 } else if (action != ' ') {
5063 *newlist = false; // use the specified list
5064 }
5065 } else if (di->di_tv.v_type == VAR_STRING
5066 && strequal((const char *)di->di_tv.vval.v_string, "$")) {
5067 if (qi->qf_listcount > 0) {
5068 qf_idx = qi->qf_listcount - 1;
5069 } else if (*newlist) {
5070 qf_idx = 0;
5071 } else {
5072 return INVALID_QFIDX;
5073 }
5074 } else {
5075 return INVALID_QFIDX;
5076 }
5077 }
5078
5079 if (!*newlist && (di = tv_dict_find(what, S_LEN("id"))) != NULL) {
5080 // Use the quickfix/location list with the specified id
5081 if (di->di_tv.v_type != VAR_NUMBER) {
5082 return INVALID_QFIDX;
5083 }
5084 return qf_id2nr(qi, (unsigned)di->di_tv.vval.v_number);
5085 }
5086
5087 return qf_idx;
5088}
5089
5090// Set the quickfix list title.
5091static int qf_setprop_title(qf_info_T *qi, int qf_idx, const dict_T *what,
5092 const dictitem_T *di)
5093 FUNC_ATTR_NONNULL_ALL
5094{
5095 if (di->di_tv.v_type != VAR_STRING) {
5096 return FAIL;
5097 }
5098
5099 xfree(qi->qf_lists[qf_idx].qf_title);
5100 qi->qf_lists[qf_idx].qf_title =
5101 (char_u *)tv_dict_get_string(what, "title", true);
5102 if (qf_idx == qi->qf_curlist) {
5103 qf_update_win_titlevar(qi);
5104 }
5105
5106 return OK;
5107}
5108
5109// Set quickfix list items/entries.
5110static int qf_setprop_items(qf_info_T *qi, int qf_idx, dictitem_T *di,
5111 int action)
5112 FUNC_ATTR_NONNULL_ALL
5113{
5114 if (di->di_tv.v_type != VAR_LIST) {
5115 return FAIL;
5116 }
5117
5118 char_u *title_save = vim_strsave(qi->qf_lists[qf_idx].qf_title);
5119 const int retval = qf_add_entries(qi, qf_idx, di->di_tv.vval.v_list,
5120 title_save,
5121 action == ' ' ? 'a' : action);
5122 xfree(title_save);
5123
5124 return retval;
5125}
5126
5127// Set quickfix list items/entries from a list of lines.
5128static int qf_setprop_items_from_lines(
5129 qf_info_T *qi,
5130 int qf_idx,
5131 const dict_T *what,
5132 dictitem_T *di,
5133 int action)
5134 FUNC_ATTR_NONNULL_ALL
5135{
5136 char_u *errorformat = p_efm;
5137 dictitem_T *efm_di;
5138 int retval = FAIL;
5139
5140 // Use the user supplied errorformat settings (if present)
5141 if ((efm_di = tv_dict_find(what, S_LEN("efm"))) != NULL) {
5142 if (efm_di->di_tv.v_type != VAR_STRING
5143 || efm_di->di_tv.vval.v_string == NULL) {
5144 return FAIL;
5145 }
5146 errorformat = efm_di->di_tv.vval.v_string;
5147 }
5148
5149 // Only a List value is supported
5150 if (di->di_tv.v_type != VAR_LIST || di->di_tv.vval.v_list == NULL) {
5151 return FAIL;
5152 }
5153
5154 if (action == 'r') {
5155 qf_free_items(qi, qf_idx);
5156 }
5157 if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat,
5158 false, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) {
5159 retval = OK;
5160 }
5161
5162 return retval;
5163}
5164
5165// Set quickfix list context.
5166static int qf_setprop_context(qf_info_T *qi, int qf_idx, dictitem_T *di)
5167 FUNC_ATTR_NONNULL_ALL
5168{
5169 tv_free(qi->qf_lists[qf_idx].qf_ctx);
5170 typval_T *ctx = xcalloc(1, sizeof(typval_T));
5171 tv_copy(&di->di_tv, ctx);
5172 qi->qf_lists[qf_idx].qf_ctx = ctx;
5173
5174 return OK;
5175}
5176
5177// Set quickfix/location list properties (title, items, context).
5178// Also used to add items from parsing a list of lines.
5179// Used by the setqflist() and setloclist() VimL functions.
5180static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action,
5181 char_u *title)
5182 FUNC_ATTR_NONNULL_ALL
5183{
5184 dictitem_T *di;
5185 int retval = FAIL;
5186 bool newlist = action == ' ' || qi->qf_curlist == qi->qf_listcount;
5187 int qf_idx = qf_setprop_get_qfidx(qi, what, action, &newlist);
5188 if (qf_idx == INVALID_QFIDX) { // List not found
5189 return FAIL;
5190 }
5191
5192 if (newlist) {
5193 qi->qf_curlist = qf_idx;
5194 qf_new_list(qi, title);
5195 qf_idx = qi->qf_curlist;
5196 }
5197
5198 if ((di = tv_dict_find(what, S_LEN("title"))) != NULL) {
5199 retval = qf_setprop_title(qi, qf_idx, what, di);
5200 }
5201 if ((di = tv_dict_find(what, S_LEN("items"))) != NULL) {
5202 retval = qf_setprop_items(qi, qf_idx, di, action);
5203 }
5204 if ((di = tv_dict_find(what, S_LEN("lines"))) != NULL) {
5205 retval = qf_setprop_items_from_lines(qi, qf_idx, what, di, action);
5206 }
5207 if ((di = tv_dict_find(what, S_LEN("context"))) != NULL) {
5208 retval = qf_setprop_context(qi, qf_idx, di);
5209 }
5210
5211 if (retval == OK) {
5212 qf_list_changed(qi, qf_idx);
5213 }
5214
5215 return retval;
5216}
5217
5218// Find the non-location list window with the specified location list.
5219static win_T * find_win_with_ll(qf_info_T *qi)
5220{
5221 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
5222 if ((wp->w_llist == qi) && !bt_quickfix(wp->w_buffer)) {
5223 return wp;
5224 }
5225 }
5226
5227 return NULL;
5228}
5229
5230// Free the entire quickfix/location list stack.
5231// If the quickfix/location list window is open, then clear it.
5232static void qf_free_stack(win_T *wp, qf_info_T *qi)
5233{
5234 win_T *qfwin = qf_find_win(qi);
5235
5236 if (qfwin != NULL) {
5237 // If the quickfix/location list window is open, then clear it
5238 if (qi->qf_curlist < qi->qf_listcount) {
5239 qf_free(qi, qi->qf_curlist);
5240 }
5241 qf_update_buffer(qi, NULL);
5242 }
5243
5244 win_T *llwin = NULL;
5245 win_T *orig_wp = wp;
5246 if (wp != NULL && IS_LL_WINDOW(wp)) {
5247 // If in the location list window, then use the non-location list
5248 // window with this location list (if present)
5249 llwin = find_win_with_ll(qi);
5250 if (llwin != NULL) {
5251 wp = llwin;
5252 }
5253 }
5254
5255 qf_free_all(wp);
5256 if (wp == NULL) {
5257 // quickfix list
5258 qi->qf_curlist = 0;
5259 qi->qf_listcount = 0;
5260 } else if (IS_LL_WINDOW(orig_wp)) {
5261 // If the location list window is open, then create a new empty location
5262 // list
5263 qf_info_T *new_ll = ll_new_list();
5264
5265 // first free the list reference in the location list window
5266 ll_free_all(&orig_wp->w_llist_ref);
5267
5268 orig_wp->w_llist_ref = new_ll;
5269 if (llwin != NULL) {
5270 llwin->w_llist = new_ll;
5271 new_ll->qf_refcount++;
5272 }
5273 }
5274}
5275
5276// Populate the quickfix list with the items supplied in the list
5277// of dictionaries. "title" will be copied to w:quickfix_title
5278// "action" is 'a' for add, 'r' for replace. Otherwise create a new list.
5279int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,
5280 dict_T *what)
5281{
5282 qf_info_T *qi = &ql_info;
5283 int retval = OK;
5284
5285 if (wp != NULL) {
5286 qi = ll_get_or_alloc_list(wp);
5287 }
5288
5289 if (action == 'f') {
5290 // Free the entire quickfix or location list stack
5291 qf_free_stack(wp, qi);
5292 } else if (what != NULL) {
5293 retval = qf_set_properties(qi, what, action, title);
5294 } else {
5295 retval = qf_add_entries(qi, qi->qf_curlist, list, title, action);
5296 if (retval == OK) {
5297 qf_list_changed(qi, qi->qf_curlist);
5298 }
5299 }
5300
5301 return retval;
5302}
5303
5304/// Mark the context as in use for all the lists in a quickfix stack.
5305static bool mark_quickfix_ctx(qf_info_T *qi, int copyID)
5306{
5307 bool abort = false;
5308
5309 for (int i = 0; i < LISTCOUNT && !abort; i++) {
5310 typval_T *ctx = qi->qf_lists[i].qf_ctx;
5311 if (ctx != NULL && ctx->v_type != VAR_NUMBER
5312 && ctx->v_type != VAR_STRING && ctx->v_type != VAR_FLOAT) {
5313 abort = set_ref_in_item(ctx, copyID, NULL, NULL);
5314 }
5315 }
5316
5317 return abort;
5318}
5319
5320/// Mark the context of the quickfix list and the location lists (if present) as
5321/// "in use". So that garbage collection doesn't free the context.
5322bool set_ref_in_quickfix(int copyID)
5323{
5324 bool abort = mark_quickfix_ctx(&ql_info, copyID);
5325 if (abort) {
5326 return abort;
5327 }
5328
5329 FOR_ALL_TAB_WINDOWS(tp, win) {
5330 if (win->w_llist != NULL) {
5331 abort = mark_quickfix_ctx(win->w_llist, copyID);
5332 if (abort) {
5333 return abort;
5334 }
5335 }
5336
5337 if (IS_LL_WINDOW(win) && (win->w_llist_ref->qf_refcount == 1)) {
5338 // In a location list window and none of the other windows is
5339 // referring to this location list. Mark the location list
5340 // context as still in use.
5341 abort = mark_quickfix_ctx(win->w_llist_ref, copyID);
5342 if (abort) {
5343 return abort;
5344 }
5345 }
5346 }
5347
5348 return abort;
5349}
5350
5351/*
5352 * ":[range]cbuffer [bufnr]" command.
5353 * ":[range]caddbuffer [bufnr]" command.
5354 * ":[range]cgetbuffer [bufnr]" command.
5355 * ":[range]lbuffer [bufnr]" command.
5356 * ":[range]laddbuffer [bufnr]" command.
5357 * ":[range]lgetbuffer [bufnr]" command.
5358 */
5359void ex_cbuffer(exarg_T *eap)
5360{
5361 buf_T *buf = NULL;
5362 qf_info_T *qi = &ql_info;
5363 const char *au_name = NULL;
5364 win_T *wp = NULL;
5365
5366 switch (eap->cmdidx) {
5367 case CMD_cbuffer:
5368 au_name = "cbuffer";
5369 break;
5370 case CMD_cgetbuffer:
5371 au_name = "cgetbuffer";
5372 break;
5373 case CMD_caddbuffer:
5374 au_name = "caddbuffer";
5375 break;
5376 case CMD_lbuffer:
5377 au_name = "lbuffer";
5378 break;
5379 case CMD_lgetbuffer:
5380 au_name = "lgetbuffer";
5381 break;
5382 case CMD_laddbuffer:
5383 au_name = "laddbuffer";
5384 break;
5385 default:
5386 break;
5387 }
5388
5389 if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, (char_u *)au_name,
5390 curbuf->b_fname, true, curbuf)) {
5391 if (aborting()) {
5392 return;
5393 }
5394 }
5395
5396 // Must come after autocommands.
5397 if (eap->cmdidx == CMD_lbuffer
5398 || eap->cmdidx == CMD_lgetbuffer
5399 || eap->cmdidx == CMD_laddbuffer) {
5400 qi = ll_get_or_alloc_list(curwin);
5401 wp = curwin;
5402 }
5403
5404 if (*eap->arg == NUL)
5405 buf = curbuf;
5406 else if (*skipwhite(skipdigits(eap->arg)) == NUL)
5407 buf = buflist_findnr(atoi((char *)eap->arg));
5408 if (buf == NULL)
5409 EMSG(_(e_invarg));
5410 else if (buf->b_ml.ml_mfp == NULL)
5411 EMSG(_("E681: Buffer is not loaded"));
5412 else {
5413 if (eap->addr_count == 0) {
5414 eap->line1 = 1;
5415 eap->line2 = buf->b_ml.ml_line_count;
5416 }
5417 if (eap->line1 < 1 || eap->line1 > buf->b_ml.ml_line_count
5418 || eap->line2 < 1 || eap->line2 > buf->b_ml.ml_line_count) {
5419 EMSG(_(e_invrange));
5420 } else {
5421 char_u *qf_title = qf_cmdtitle(*eap->cmdlinep);
5422
5423 if (buf->b_sfname) {
5424 vim_snprintf((char *)IObuff, IOSIZE, "%s (%s)",
5425 (char *)qf_title, (char *)buf->b_sfname);
5426 qf_title = IObuff;
5427 }
5428
5429 int res = qf_init_ext(qi, qi->qf_curlist, NULL, buf, NULL, p_efm,
5430 (eap->cmdidx != CMD_caddbuffer
5431 && eap->cmdidx != CMD_laddbuffer),
5432 eap->line1, eap->line2, qf_title, NULL);
5433 if (res >= 0) {
5434 qf_list_changed(qi, qi->qf_curlist);
5435 }
5436 // Remember the current quickfix list identifier, so that we can
5437 // check for autocommands changing the current quickfix list.
5438 unsigned save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
5439 if (au_name != NULL) {
5440 const buf_T *const curbuf_old = curbuf;
5441 apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)au_name,
5442 curbuf->b_fname, true, curbuf);
5443 if (curbuf != curbuf_old) {
5444 // Autocommands changed buffer, don't jump now, "qi" may
5445 // be invalid.
5446 res = 0;
5447 }
5448 }
5449 // Jump to the first error for new list and if autocmds didn't
5450 // free the list.
5451 if (res > 0 && (eap->cmdidx == CMD_cbuffer || eap->cmdidx == CMD_lbuffer)
5452 && qflist_valid(wp, save_qfid)) {
5453 // display the first error
5454 qf_jump_first(qi, save_qfid, eap->forceit);
5455 }
5456 }
5457 }
5458}
5459
5460/*
5461 * ":cexpr {expr}", ":cgetexpr {expr}", ":caddexpr {expr}" command.
5462 * ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command.
5463 */
5464void ex_cexpr(exarg_T *eap)
5465{
5466 qf_info_T *qi = &ql_info;
5467 const char *au_name = NULL;
5468 win_T *wp = NULL;
5469
5470 switch (eap->cmdidx) {
5471 case CMD_cexpr:
5472 au_name = "cexpr";
5473 break;
5474 case CMD_cgetexpr:
5475 au_name = "cgetexpr";
5476 break;
5477 case CMD_caddexpr:
5478 au_name = "caddexpr";
5479 break;
5480 case CMD_lexpr:
5481 au_name = "lexpr";
5482 break;
5483 case CMD_lgetexpr:
5484 au_name = "lgetexpr";
5485 break;
5486 case CMD_laddexpr:
5487 au_name = "laddexpr";
5488 break;
5489 default:
5490 break;
5491 }
5492 if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, (char_u *)au_name,
5493 curbuf->b_fname, true, curbuf)) {
5494 if (aborting()) {
5495 return;
5496 }
5497 }
5498
5499 if (eap->cmdidx == CMD_lexpr
5500 || eap->cmdidx == CMD_lgetexpr
5501 || eap->cmdidx == CMD_laddexpr) {
5502 qi = ll_get_or_alloc_list(curwin);
5503 wp = curwin;
5504 }
5505
5506 /* Evaluate the expression. When the result is a string or a list we can
5507 * use it to fill the errorlist. */
5508 typval_T tv;
5509 if (eval0(eap->arg, &tv, NULL, true) != FAIL) {
5510 if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL)
5511 || tv.v_type == VAR_LIST) {
5512 int res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, &tv, p_efm,
5513 (eap->cmdidx != CMD_caddexpr
5514 && eap->cmdidx != CMD_laddexpr),
5515 (linenr_T)0, (linenr_T)0,
5516 qf_cmdtitle(*eap->cmdlinep), NULL);
5517 if (res >= 0) {
5518 qf_list_changed(qi, qi->qf_curlist);
5519 }
5520 // Remember the current quickfix list identifier, so that we can
5521 // check for autocommands changing the current quickfix list.
5522 unsigned save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
5523 if (au_name != NULL) {
5524 apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)au_name,
5525 curbuf->b_fname, true, curbuf);
5526 }
5527 // Jump to the first error for a new list and if autocmds didn't
5528 // free the list.
5529 if (res > 0
5530 && (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr)
5531 && qflist_valid(wp, save_qfid)) {
5532 // display the first error
5533 qf_jump_first(qi, save_qfid, eap->forceit);
5534 }
5535 } else {
5536 EMSG(_("E777: String or List expected"));
5537 }
5538 tv_clear(&tv);
5539 }
5540}
5541
5542/*
5543 * ":helpgrep {pattern}"
5544 */
5545void ex_helpgrep(exarg_T *eap)
5546{
5547 regmatch_T regmatch;
5548 char_u *save_cpo;
5549 char_u *p;
5550 int fcount;
5551 char_u **fnames;
5552 FILE *fd;
5553 int fi;
5554 long lnum;
5555 char_u *lang;
5556 qf_info_T *qi = &ql_info;
5557 int new_qi = FALSE;
5558 char_u *au_name = NULL;
5559
5560 /* Check for a specified language */
5561 lang = check_help_lang(eap->arg);
5562
5563 switch (eap->cmdidx) {
5564 case CMD_helpgrep: au_name = (char_u *)"helpgrep"; break;
5565 case CMD_lhelpgrep: au_name = (char_u *)"lhelpgrep"; break;
5566 default: break;
5567 }
5568 if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
5569 curbuf->b_fname, true, curbuf)) {
5570 if (aborting()) {
5571 return;
5572 }
5573 }
5574
5575 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
5576 save_cpo = p_cpo;
5577 p_cpo = empty_option;
5578
5579 if (eap->cmdidx == CMD_lhelpgrep) {
5580 win_T *wp = NULL;
5581
5582 // If the current window is a help window, then use it
5583 if (bt_help(curwin->w_buffer)) {
5584 wp = curwin;
5585 } else {
5586 // Find an existing help window
5587 FOR_ALL_WINDOWS_IN_TAB(wp2, curtab) {
5588 if (bt_help(wp2->w_buffer)) {
5589 wp = wp2;
5590 break;
5591 }
5592 }
5593 }
5594
5595 if (wp == NULL) { // Help window not found
5596 qi = NULL;
5597 } else {
5598 qi = wp->w_llist;
5599 }
5600 if (qi == NULL) {
5601 /* Allocate a new location list for help text matches */
5602 qi = ll_new_list();
5603 new_qi = TRUE;
5604 }
5605 }
5606
5607 regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING);
5608 regmatch.rm_ic = FALSE;
5609 if (regmatch.regprog != NULL) {
5610 // Create a new quickfix list.
5611 qf_new_list(qi, qf_cmdtitle(*eap->cmdlinep));
5612
5613 // Go through all the directories in 'runtimepath'
5614 p = p_rtp;
5615 while (*p != NUL && !got_int) {
5616 copy_option_part(&p, NameBuff, MAXPATHL, ",");
5617
5618 /* Find all "*.txt" and "*.??x" files in the "doc" directory. */
5619 add_pathsep((char *)NameBuff);
5620 STRCAT(NameBuff, "doc/*.\\(txt\\|??x\\)");
5621
5622 // Note: We cannot just do `&NameBuff` because it is a statically sized array
5623 // so `NameBuff == &NameBuff` according to C semantics.
5624 char_u *buff_list[1] = {NameBuff};
5625 if (gen_expand_wildcards(1, buff_list, &fcount,
5626 &fnames, EW_FILE|EW_SILENT) == OK
5627 && fcount > 0) {
5628 for (fi = 0; fi < fcount && !got_int; fi++) {
5629 // Skip files for a different language.
5630 if (lang != NULL
5631 && STRNICMP(lang, fnames[fi] + STRLEN(fnames[fi]) - 3, 2) != 0
5632 && !(STRNICMP(lang, "en", 2) == 0
5633 && STRNICMP("txt", fnames[fi]
5634 + STRLEN(fnames[fi]) - 3, 3) == 0)) {
5635 continue;
5636 }
5637 fd = os_fopen((char *)fnames[fi], "r");
5638 if (fd != NULL) {
5639 lnum = 1;
5640 while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) {
5641 char_u *line = IObuff;
5642 if (vim_regexec(&regmatch, line, (colnr_T)0)) {
5643 int l = (int)STRLEN(line);
5644
5645 /* remove trailing CR, LF, spaces, etc. */
5646 while (l > 0 && line[l - 1] <= ' ')
5647 line[--l] = NUL;
5648
5649 if (qf_add_entry(qi,
5650 qi->qf_curlist,
5651 NULL, // dir
5652 fnames[fi],
5653 NULL,
5654 0,
5655 line,
5656 lnum,
5657 (int)(regmatch.startp[0] - line)
5658 + 1, // col
5659 false, // vis_col
5660 NULL, // search pattern
5661 0, // nr
5662 1, // type
5663 true) // valid
5664 == FAIL) {
5665 got_int = true;
5666 if (line != IObuff) {
5667 xfree(line);
5668 }
5669 break;
5670 }
5671 }
5672 if (line != IObuff)
5673 xfree(line);
5674 ++lnum;
5675 line_breakcheck();
5676 }
5677 fclose(fd);
5678 }
5679 }
5680 FreeWild(fcount, fnames);
5681 }
5682 }
5683
5684 vim_regfree(regmatch.regprog);
5685
5686 qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE;
5687 qi->qf_lists[qi->qf_curlist].qf_ptr =
5688 qi->qf_lists[qi->qf_curlist].qf_start;
5689 qi->qf_lists[qi->qf_curlist].qf_index = 1;
5690 }
5691
5692 if (p_cpo == empty_option)
5693 p_cpo = save_cpo;
5694 else
5695 /* Darn, some plugin changed the value. */
5696 free_string_option(save_cpo);
5697
5698 qf_list_changed(qi, qi->qf_curlist);
5699 qf_update_buffer(qi, NULL);
5700
5701 if (au_name != NULL) {
5702 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
5703 curbuf->b_fname, true, curbuf);
5704 if (!new_qi && IS_LL_STACK(qi) && qf_find_buf(qi) == NULL) {
5705 // autocommands made "qi" invalid
5706 return;
5707 }
5708 }
5709
5710 /* Jump to first match. */
5711 if (qi->qf_lists[qi->qf_curlist].qf_count > 0)
5712 qf_jump(qi, 0, 0, FALSE);
5713 else
5714 EMSG2(_(e_nomatch2), eap->arg);
5715
5716 if (eap->cmdidx == CMD_lhelpgrep) {
5717 /* If the help window is not opened or if it already points to the
5718 * correct location list, then free the new location list. */
5719 if (!bt_help(curwin->w_buffer) || curwin->w_llist == qi) {
5720 if (new_qi) {
5721 ll_free_all(&qi);
5722 }
5723 } else if (curwin->w_llist == NULL) {
5724 curwin->w_llist = qi;
5725 }
5726 }
5727}
5728
5729