xref: /vim-8.2.3635/src/quickfix.c (revision 777175b0)
1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2071d4279SBram Moolenaar  *
3071d4279SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
4071d4279SBram Moolenaar  *
5071d4279SBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
6071d4279SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
7071d4279SBram Moolenaar  * See README.txt for an overview of the Vim source code.
8071d4279SBram Moolenaar  */
9071d4279SBram Moolenaar 
10071d4279SBram Moolenaar /*
11071d4279SBram Moolenaar  * quickfix.c: functions for quickfix mode, using a file with error messages
12071d4279SBram Moolenaar  */
13071d4279SBram Moolenaar 
14071d4279SBram Moolenaar #include "vim.h"
15071d4279SBram Moolenaar 
16071d4279SBram Moolenaar #if defined(FEAT_QUICKFIX) || defined(PROTO)
17071d4279SBram Moolenaar 
18071d4279SBram Moolenaar struct dir_stack_T
19071d4279SBram Moolenaar {
20071d4279SBram Moolenaar     struct dir_stack_T	*next;
21071d4279SBram Moolenaar     char_u		*dirname;
22071d4279SBram Moolenaar };
23071d4279SBram Moolenaar 
24071d4279SBram Moolenaar /*
2568b76a69SBram Moolenaar  * For each error the next struct is allocated and linked in a list.
26071d4279SBram Moolenaar  */
2768b76a69SBram Moolenaar typedef struct qfline_S qfline_T;
2868b76a69SBram Moolenaar struct qfline_S
29071d4279SBram Moolenaar {
3000bf8cd2SBram Moolenaar     qfline_T	*qf_next;	// pointer to next error in the list
3100bf8cd2SBram Moolenaar     qfline_T	*qf_prev;	// pointer to previous error in the list
3200bf8cd2SBram Moolenaar     linenr_T	qf_lnum;	// line number where the error occurred
336864efa5Sthinca     linenr_T	qf_end_lnum;	// line number when the error has range or zero
3400bf8cd2SBram Moolenaar     int		qf_fnum;	// file number for the line
3500bf8cd2SBram Moolenaar     int		qf_col;		// column where the error occurred
366864efa5Sthinca     int		qf_end_col;	// column when the error has range or zero
3700bf8cd2SBram Moolenaar     int		qf_nr;		// error number
3800bf8cd2SBram Moolenaar     char_u	*qf_module;	// module name for this error
3900bf8cd2SBram Moolenaar     char_u	*qf_pattern;	// search pattern for the error
4000bf8cd2SBram Moolenaar     char_u	*qf_text;	// description of the error
416864efa5Sthinca     char_u	qf_viscol;	// set to TRUE if qf_col and qf_end_col is
426864efa5Sthinca 				// screen column
4300bf8cd2SBram Moolenaar     char_u	qf_cleared;	// set to TRUE if line has been deleted
4400bf8cd2SBram Moolenaar     char_u	qf_type;	// type of the error (mostly 'E'); 1 for
4500bf8cd2SBram Moolenaar 				// :helpgrep
4600bf8cd2SBram Moolenaar     char_u	qf_valid;	// valid error message detected
47071d4279SBram Moolenaar };
48071d4279SBram Moolenaar 
49071d4279SBram Moolenaar /*
50071d4279SBram Moolenaar  * There is a stack of error lists.
51071d4279SBram Moolenaar  */
52071d4279SBram Moolenaar #define LISTCOUNT   10
53a2aa8a2bSBram Moolenaar #define INVALID_QFIDX (-1)
54ee8188fcSBram Moolenaar #define INVALID_QFBUFNR (0)
55071d4279SBram Moolenaar 
566a8958dbSBram Moolenaar /*
572d67d307SBram Moolenaar  * Quickfix list type.
582d67d307SBram Moolenaar  */
592d67d307SBram Moolenaar typedef enum
602d67d307SBram Moolenaar {
612d67d307SBram Moolenaar     QFLT_QUICKFIX, // Quickfix list - global list
622d67d307SBram Moolenaar     QFLT_LOCATION, // Location list - per window list
632d67d307SBram Moolenaar     QFLT_INTERNAL  // Internal - Temporary list used by getqflist()/getloclist()
642d67d307SBram Moolenaar } qfltype_T;
652d67d307SBram Moolenaar 
662d67d307SBram Moolenaar /*
676a8958dbSBram Moolenaar  * Quickfix/Location list definition
686a8958dbSBram Moolenaar  * Contains a list of entries (qfline_T). qf_start points to the first entry
696a8958dbSBram Moolenaar  * and qf_last points to the last entry. qf_count contains the list size.
706a8958dbSBram Moolenaar  *
716a8958dbSBram Moolenaar  * Usually the list contains one or more entries. But an empty list can be
726a8958dbSBram Moolenaar  * created using setqflist()/setloclist() with a title and/or user context
736a8958dbSBram Moolenaar  * information and entries can be added later using setqflist()/setloclist().
746a8958dbSBram Moolenaar  */
75d12f5c17SBram Moolenaar typedef struct qf_list_S
76071d4279SBram Moolenaar {
7700bf8cd2SBram Moolenaar     int_u	qf_id;		// Unique identifier for this list
782d67d307SBram Moolenaar     qfltype_T	qfl_type;
7900bf8cd2SBram Moolenaar     qfline_T	*qf_start;	// pointer to the first error
8000bf8cd2SBram Moolenaar     qfline_T	*qf_last;	// pointer to the last error
8100bf8cd2SBram Moolenaar     qfline_T	*qf_ptr;	// pointer to the current error
8200bf8cd2SBram Moolenaar     int		qf_count;	// number of errors (0 means empty list)
8300bf8cd2SBram Moolenaar     int		qf_index;	// current index in the error list
8400bf8cd2SBram Moolenaar     int		qf_nonevalid;	// TRUE if not a single valid entry found
8500bf8cd2SBram Moolenaar     char_u	*qf_title;	// title derived from the command that created
8600bf8cd2SBram Moolenaar 				// the error list or set by setqflist
8700bf8cd2SBram Moolenaar     typval_T	*qf_ctx;	// context set by setqflist/setloclist
88d43906d2SBram Moolenaar     callback_T  qftf_cb;	// 'quickfixtextfunc' callback function
89a7df8c70SBram Moolenaar 
90a7df8c70SBram Moolenaar     struct dir_stack_T	*qf_dir_stack;
91a7df8c70SBram Moolenaar     char_u		*qf_directory;
92a7df8c70SBram Moolenaar     struct dir_stack_T	*qf_file_stack;
93a7df8c70SBram Moolenaar     char_u		*qf_currfile;
94a7df8c70SBram Moolenaar     int			qf_multiline;
95a7df8c70SBram Moolenaar     int			qf_multiignore;
96a7df8c70SBram Moolenaar     int			qf_multiscan;
97b254af31SBram Moolenaar     long		qf_changedtick;
98d12f5c17SBram Moolenaar } qf_list_T;
99071d4279SBram Moolenaar 
1006a8958dbSBram Moolenaar /*
1016a8958dbSBram Moolenaar  * Quickfix/Location list stack definition
1026a8958dbSBram Moolenaar  * Contains a list of quickfix/location lists (qf_list_T)
1036a8958dbSBram Moolenaar  */
104d12f5c17SBram Moolenaar struct qf_info_S
105d12f5c17SBram Moolenaar {
10600bf8cd2SBram Moolenaar     // Count of references to this list. Used only for location lists.
10700bf8cd2SBram Moolenaar     // When a location list window reference this list, qf_refcount
10800bf8cd2SBram Moolenaar     // will be 2. Otherwise, qf_refcount will be 1. When qf_refcount
10900bf8cd2SBram Moolenaar     // reaches 0, the list is freed.
110d12f5c17SBram Moolenaar     int		qf_refcount;
11100bf8cd2SBram Moolenaar     int		qf_listcount;	    // current number of lists
11200bf8cd2SBram Moolenaar     int		qf_curlist;	    // current error list
113d12f5c17SBram Moolenaar     qf_list_T	qf_lists[LISTCOUNT];
1142d67d307SBram Moolenaar     qfltype_T	qfl_type;	    // type of list
115ee8188fcSBram Moolenaar     int		qf_bufnr;	    // quickfix window buffer number
116d12f5c17SBram Moolenaar };
117d12f5c17SBram Moolenaar 
11800bf8cd2SBram Moolenaar static qf_info_T ql_info;	// global quickfix list
11900bf8cd2SBram Moolenaar static int_u last_qf_id = 0;	// Last used quickfix list id
120071d4279SBram Moolenaar 
12100bf8cd2SBram Moolenaar #define FMT_PATTERNS 11		// maximum number of % recognized
122071d4279SBram Moolenaar 
123071d4279SBram Moolenaar /*
124071d4279SBram Moolenaar  * Structure used to hold the info of one part of 'errorformat'
125071d4279SBram Moolenaar  */
1260126585dSBram Moolenaar typedef struct efm_S efm_T;
1270126585dSBram Moolenaar struct efm_S
128071d4279SBram Moolenaar {
12900bf8cd2SBram Moolenaar     regprog_T	    *prog;	// pre-formatted part of 'errorformat'
13000bf8cd2SBram Moolenaar     efm_T	    *next;	// pointer to next (NULL if last)
13100bf8cd2SBram Moolenaar     char_u	    addr[FMT_PATTERNS]; // indices of used % patterns
13200bf8cd2SBram Moolenaar     char_u	    prefix;	// prefix of this format line:
13300bf8cd2SBram Moolenaar 				//   'D' enter directory
13400bf8cd2SBram Moolenaar 				//   'X' leave directory
13500bf8cd2SBram Moolenaar 				//   'A' start of multi-line message
13600bf8cd2SBram Moolenaar 				//   'E' error message
13700bf8cd2SBram Moolenaar 				//   'W' warning message
13800bf8cd2SBram Moolenaar 				//   'I' informational message
139e928366dSBram Moolenaar 				//   'N' note message
14000bf8cd2SBram Moolenaar 				//   'C' continuation line
14100bf8cd2SBram Moolenaar 				//   'Z' end of multi-line message
14200bf8cd2SBram Moolenaar 				//   'G' general, unspecific message
14300bf8cd2SBram Moolenaar 				//   'P' push file (partial) message
14400bf8cd2SBram Moolenaar 				//   'Q' pop/quit file (partial) message
14500bf8cd2SBram Moolenaar 				//   'O' overread (partial) message
14600bf8cd2SBram Moolenaar     char_u	    flags;	// additional flags given in prefix
14700bf8cd2SBram Moolenaar 				//   '-' do not include this line
14800bf8cd2SBram Moolenaar 				//   '+' include whole line in message
14900bf8cd2SBram Moolenaar     int		    conthere;	// %> used
150071d4279SBram Moolenaar };
151071d4279SBram Moolenaar 
1529f84ded3SBram Moolenaar // List of location lists to be deleted.
1539f84ded3SBram Moolenaar // Used to delay the deletion of locations lists by autocmds.
1549f84ded3SBram Moolenaar typedef struct qf_delq_S
1559f84ded3SBram Moolenaar {
1569f84ded3SBram Moolenaar     struct qf_delq_S	*next;
1579f84ded3SBram Moolenaar     qf_info_T		*qi;
1589f84ded3SBram Moolenaar } qf_delq_T;
1599f84ded3SBram Moolenaar static qf_delq_T *qf_delq_head = NULL;
1609f84ded3SBram Moolenaar 
1619f84ded3SBram Moolenaar // Counter to prevent autocmds from freeing up location lists when they are
1629f84ded3SBram Moolenaar // still being used.
1639f84ded3SBram Moolenaar static int	quickfix_busy = 0;
1649f84ded3SBram Moolenaar 
16500bf8cd2SBram Moolenaar static efm_T	*fmt_start = NULL; // cached across qf_parse_line() calls
16663bed3d3SBram Moolenaar 
167d43906d2SBram Moolenaar // callback function for 'quickfixtextfunc'
168d43906d2SBram Moolenaar static callback_T qftf_cb;
169d43906d2SBram Moolenaar 
170baaa7e9eSBram Moolenaar static void	qf_new_list(qf_info_T *qi, char_u *qf_title);
1716864efa5Sthinca static int	qf_add_entry(qf_list_T *qfl, char_u *dir, char_u *fname, char_u *module, int bufnum, char_u *mesg, long lnum, long end_lnum, int col, int end_col, int vis_col, char_u *pattern, int nr, int type, int valid);
172fe15b7dfSBram Moolenaar static void	qf_free(qf_list_T *qfl);
173baaa7e9eSBram Moolenaar static char_u	*qf_types(int, int);
1740398e00aSBram Moolenaar static int	qf_get_fnum(qf_list_T *qfl, char_u *, char_u *);
175361c8f0eSBram Moolenaar static char_u	*qf_push_dir(char_u *, struct dir_stack_T **, int is_file_stack);
176baaa7e9eSBram Moolenaar static char_u	*qf_pop_dir(struct dir_stack_T **);
177fe15b7dfSBram Moolenaar static char_u	*qf_guess_filepath(qf_list_T *qfl, char_u *);
1785843f5f3SBram Moolenaar static void	qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, int newwin);
179baaa7e9eSBram Moolenaar static void	qf_fmt_text(char_u *text, char_u *buf, int bufsize);
1806864efa5Sthinca static void	qf_range_text(qfline_T *qfp, char_u *buf, int bufsize);
181baaa7e9eSBram Moolenaar static int	qf_win_pos_update(qf_info_T *qi, int old_qf_index);
182baaa7e9eSBram Moolenaar static win_T	*qf_find_win(qf_info_T *qi);
183baaa7e9eSBram Moolenaar static buf_T	*qf_find_buf(qf_info_T *qi);
184864293abSBram Moolenaar static void	qf_update_buffer(qf_info_T *qi, qfline_T *old_last);
1857ba5a7efSBram Moolenaar static void	qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid);
186baaa7e9eSBram Moolenaar static buf_T	*load_dummy_buffer(char_u *fname, char_u *dirname_start, char_u *resulting_dir);
187baaa7e9eSBram Moolenaar static void	wipe_dummy_buffer(buf_T *buf, char_u *dirname_start);
188baaa7e9eSBram Moolenaar static void	unload_dummy_buffer(buf_T *buf, char_u *dirname_start);
189baaa7e9eSBram Moolenaar static qf_info_T *ll_get_or_alloc_list(win_T *);
1903ff33114SBram Moolenaar static char_u	*e_no_more_items = (char_u *)N_("E553: No more items");
191071d4279SBram Moolenaar 
19200bf8cd2SBram Moolenaar // Quickfix window check helper macro
193d12f5c17SBram Moolenaar #define IS_QF_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref == NULL)
19400bf8cd2SBram Moolenaar // Location list window check helper macro
195d12f5c17SBram Moolenaar #define IS_LL_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL)
1964d77c65aSBram Moolenaar 
1974d77c65aSBram Moolenaar // Quickfix and location list stack check helper macros
1982d67d307SBram Moolenaar #define IS_QF_STACK(qi)		(qi->qfl_type == QFLT_QUICKFIX)
1992d67d307SBram Moolenaar #define IS_LL_STACK(qi)		(qi->qfl_type == QFLT_LOCATION)
2002d67d307SBram Moolenaar #define IS_QF_LIST(qfl)		(qfl->qfl_type == QFLT_QUICKFIX)
2012d67d307SBram Moolenaar #define IS_LL_LIST(qfl)		(qfl->qfl_type == QFLT_LOCATION)
2024d77c65aSBram Moolenaar 
203d12f5c17SBram Moolenaar /*
204d12f5c17SBram Moolenaar  * Return location list for window 'wp'
205d12f5c17SBram Moolenaar  * For location list window, return the referenced location list
206d12f5c17SBram Moolenaar  */
207d12f5c17SBram Moolenaar #define GET_LOC_LIST(wp) (IS_LL_WINDOW(wp) ? wp->w_llist_ref : wp->w_llist)
208d12f5c17SBram Moolenaar 
20995946f12SBram Moolenaar // Macro to loop through all the items in a quickfix list
21095946f12SBram Moolenaar // Quickfix item index starts from 1, so i below starts at 1
211a16123a6SBram Moolenaar #define FOR_ALL_QFL_ITEMS(qfl, qfp, i) \
21295946f12SBram Moolenaar 		    for (i = 1, qfp = qfl->qf_start; \
21395946f12SBram Moolenaar 			    !got_int && i <= qfl->qf_count && qfp != NULL; \
214a16123a6SBram Moolenaar 			    ++i, qfp = qfp->qf_next)
215a16123a6SBram Moolenaar 
216071d4279SBram Moolenaar /*
2176dd4a535SBram Moolenaar  * Looking up a buffer can be slow if there are many.  Remember the last one
2186dd4a535SBram Moolenaar  * to make this a lot faster if there are multiple matches in the same file.
2196dd4a535SBram Moolenaar  */
2206dd4a535SBram Moolenaar static char_u   *qf_last_bufname = NULL;
22145e5fd13SBram Moolenaar static bufref_T  qf_last_bufref = {NULL, 0, 0};
2226dd4a535SBram Moolenaar 
2234d170af0SBram Moolenaar static char	*e_current_quickfix_list_was_changed =
2244d170af0SBram Moolenaar 				 N_("E925: Current quickfix list was changed");
2254d170af0SBram Moolenaar static char	*e_current_location_list_was_changed =
2263c097226SBram Moolenaar 				 N_("E926: Current location list was changed");
2273c097226SBram Moolenaar 
2286dd4a535SBram Moolenaar /*
2296be8c8e1SBram Moolenaar  * Maximum number of bytes allowed per line while reading a errorfile.
2306be8c8e1SBram Moolenaar  */
2316be8c8e1SBram Moolenaar #define LINE_MAXLEN 4096
2326be8c8e1SBram Moolenaar 
233071d4279SBram Moolenaar static struct fmtpattern
234071d4279SBram Moolenaar {
235071d4279SBram Moolenaar     char_u	convchar;
236071d4279SBram Moolenaar     char	*pattern;
237071d4279SBram Moolenaar } fmt_pat[FMT_PATTERNS] =
238071d4279SBram Moolenaar     {
23900bf8cd2SBram Moolenaar 	{'f', ".\\+"},	    // only used when at end
240071d4279SBram Moolenaar 	{'n', "\\d\\+"},
241071d4279SBram Moolenaar 	{'l', "\\d\\+"},
242071d4279SBram Moolenaar 	{'c', "\\d\\+"},
243071d4279SBram Moolenaar 	{'t', "."},
244071d4279SBram Moolenaar 	{'m', ".\\+"},
245071d4279SBram Moolenaar 	{'r', ".*"},
246071d4279SBram Moolenaar 	{'p', "[- 	.]*"},
24768b76a69SBram Moolenaar 	{'v', "\\d\\+"},
248d76ce852SBram Moolenaar 	{'s', ".\\+"},
249d76ce852SBram Moolenaar 	{'o', ".\\+"}
250071d4279SBram Moolenaar     };
251071d4279SBram Moolenaar 
252688e3d1fSBram Moolenaar /*
2536bff719fSBram Moolenaar  * Convert an errorformat pattern to a regular expression pattern.
254de3b3677SBram Moolenaar  * See fmt_pat definition above for the list of supported patterns.  The
255de3b3677SBram Moolenaar  * pattern specifier is supplied in "efmpat".  The converted pattern is stored
256de3b3677SBram Moolenaar  * in "regpat".  Returns a pointer to the location after the pattern.
257688e3d1fSBram Moolenaar  */
2586bff719fSBram Moolenaar     static char_u *
efmpat_to_regpat(char_u * efmpat,char_u * regpat,efm_T * efminfo,int idx,int round)259de3b3677SBram Moolenaar efmpat_to_regpat(
260de3b3677SBram Moolenaar 	char_u	*efmpat,
261de3b3677SBram Moolenaar 	char_u	*regpat,
262de3b3677SBram Moolenaar 	efm_T	*efminfo,
2636bff719fSBram Moolenaar 	int	idx,
264f9e3e09fSBram Moolenaar 	int	round)
265071d4279SBram Moolenaar {
266688e3d1fSBram Moolenaar     char_u	*srcptr;
267071d4279SBram Moolenaar 
268de3b3677SBram Moolenaar     if (efminfo->addr[idx])
269071d4279SBram Moolenaar     {
27000bf8cd2SBram Moolenaar 	// Each errorformat pattern can occur only once
271f9e3e09fSBram Moolenaar 	semsg(_("E372: Too many %%%c in format string"), *efmpat);
2726bff719fSBram Moolenaar 	return NULL;
273071d4279SBram Moolenaar     }
2746bff719fSBram Moolenaar     if ((idx && idx < 6
275de3b3677SBram Moolenaar 		&& vim_strchr((char_u *)"DXOPQ", efminfo->prefix) != NULL)
276071d4279SBram Moolenaar 	    || (idx == 6
277de3b3677SBram Moolenaar 		&& vim_strchr((char_u *)"OPQ", efminfo->prefix) == NULL))
278071d4279SBram Moolenaar     {
279f9e3e09fSBram Moolenaar 	semsg(_("E373: Unexpected %%%c in format string"), *efmpat);
2806bff719fSBram Moolenaar 	return NULL;
281071d4279SBram Moolenaar     }
282de3b3677SBram Moolenaar     efminfo->addr[idx] = (char_u)++round;
283de3b3677SBram Moolenaar     *regpat++ = '\\';
284de3b3677SBram Moolenaar     *regpat++ = '(';
285071d4279SBram Moolenaar #ifdef BACKSLASH_IN_FILENAME
286de3b3677SBram Moolenaar     if (*efmpat == 'f')
287071d4279SBram Moolenaar     {
28800bf8cd2SBram Moolenaar 	// Also match "c:" in the file name, even when
28900bf8cd2SBram Moolenaar 	// checking for a colon next: "%f:".
29000bf8cd2SBram Moolenaar 	// "\%(\a:\)\="
291de3b3677SBram Moolenaar 	STRCPY(regpat, "\\%(\\a:\\)\\=");
292de3b3677SBram Moolenaar 	regpat += 10;
293071d4279SBram Moolenaar     }
294071d4279SBram Moolenaar #endif
295de3b3677SBram Moolenaar     if (*efmpat == 'f' && efmpat[1] != NUL)
296071d4279SBram Moolenaar     {
297de3b3677SBram Moolenaar 	if (efmpat[1] != '\\' && efmpat[1] != '%')
298e344beadSBram Moolenaar 	{
29900bf8cd2SBram Moolenaar 	    // A file name may contain spaces, but this isn't
30000bf8cd2SBram Moolenaar 	    // in "\f".  For "%f:%l:%m" there may be a ":" in
30100bf8cd2SBram Moolenaar 	    // the file name.  Use ".\{-1,}x" instead (x is
30200bf8cd2SBram Moolenaar 	    // the next character), the requirement that :999:
30300bf8cd2SBram Moolenaar 	    // follows should work.
304de3b3677SBram Moolenaar 	    STRCPY(regpat, ".\\{-1,}");
305de3b3677SBram Moolenaar 	    regpat += 7;
306071d4279SBram Moolenaar 	}
307071d4279SBram Moolenaar 	else
308071d4279SBram Moolenaar 	{
30900bf8cd2SBram Moolenaar 	    // File name followed by '\\' or '%': include as
31000bf8cd2SBram Moolenaar 	    // many file name chars as possible.
311de3b3677SBram Moolenaar 	    STRCPY(regpat, "\\f\\+");
312de3b3677SBram Moolenaar 	    regpat += 4;
313e344beadSBram Moolenaar 	}
314e344beadSBram Moolenaar     }
315e344beadSBram Moolenaar     else
316e344beadSBram Moolenaar     {
317071d4279SBram Moolenaar 	srcptr = (char_u *)fmt_pat[idx].pattern;
318de3b3677SBram Moolenaar 	while ((*regpat = *srcptr++) != NUL)
319de3b3677SBram Moolenaar 	    ++regpat;
320071d4279SBram Moolenaar     }
321de3b3677SBram Moolenaar     *regpat++ = '\\';
322de3b3677SBram Moolenaar     *regpat++ = ')';
3236bff719fSBram Moolenaar 
324de3b3677SBram Moolenaar     return regpat;
325071d4279SBram Moolenaar }
3266bff719fSBram Moolenaar 
3276bff719fSBram Moolenaar /*
3286bff719fSBram Moolenaar  * Convert a scanf like format in 'errorformat' to a regular expression.
329de3b3677SBram Moolenaar  * Returns a pointer to the location after the pattern.
3306bff719fSBram Moolenaar  */
3316bff719fSBram Moolenaar     static char_u *
scanf_fmt_to_regpat(char_u ** pefmp,char_u * efm,int len,char_u * regpat)3326bff719fSBram Moolenaar scanf_fmt_to_regpat(
333de3b3677SBram Moolenaar 	char_u	**pefmp,
3346bff719fSBram Moolenaar 	char_u	*efm,
3356bff719fSBram Moolenaar 	int	len,
336f9e3e09fSBram Moolenaar 	char_u	*regpat)
337071d4279SBram Moolenaar {
3386bff719fSBram Moolenaar     char_u	*efmp = *pefmp;
3396bff719fSBram Moolenaar 
340de3b3677SBram Moolenaar     if (*efmp == '[' || *efmp == '\\')
341071d4279SBram Moolenaar     {
34200bf8cd2SBram Moolenaar 	if ((*regpat++ = *efmp) == '[')	// %*[^a-z0-9] etc.
343071d4279SBram Moolenaar 	{
344071d4279SBram Moolenaar 	    if (efmp[1] == '^')
345de3b3677SBram Moolenaar 		*regpat++ = *++efmp;
346071d4279SBram Moolenaar 	    if (efmp < efm + len)
347071d4279SBram Moolenaar 	    {
34800bf8cd2SBram Moolenaar 		*regpat++ = *++efmp;	    // could be ']'
349071d4279SBram Moolenaar 		while (efmp < efm + len
350de3b3677SBram Moolenaar 			&& (*regpat++ = *++efmp) != ']')
35100bf8cd2SBram Moolenaar 		    // skip ;
352071d4279SBram Moolenaar 		if (efmp == efm + len)
353071d4279SBram Moolenaar 		{
354f9e3e09fSBram Moolenaar 		    emsg(_("E374: Missing ] in format string"));
3556bff719fSBram Moolenaar 		    return NULL;
356071d4279SBram Moolenaar 		}
357071d4279SBram Moolenaar 	    }
358071d4279SBram Moolenaar 	}
35900bf8cd2SBram Moolenaar 	else if (efmp < efm + len)	// %*\D, %*\s etc.
360de3b3677SBram Moolenaar 	    *regpat++ = *++efmp;
361de3b3677SBram Moolenaar 	*regpat++ = '\\';
362de3b3677SBram Moolenaar 	*regpat++ = '+';
363071d4279SBram Moolenaar     }
364071d4279SBram Moolenaar     else
365071d4279SBram Moolenaar     {
36600bf8cd2SBram Moolenaar 	// TODO: scanf()-like: %*ud, %*3c, %*f, ... ?
367f9e3e09fSBram Moolenaar 	semsg(_("E375: Unsupported %%%c in format string"), *efmp);
3686bff719fSBram Moolenaar 	return NULL;
369071d4279SBram Moolenaar     }
3706bff719fSBram Moolenaar 
3716bff719fSBram Moolenaar     *pefmp = efmp;
3726bff719fSBram Moolenaar 
373de3b3677SBram Moolenaar     return regpat;
374071d4279SBram Moolenaar }
3756bff719fSBram Moolenaar 
3766bff719fSBram Moolenaar /*
3776bff719fSBram Moolenaar  * Analyze/parse an errorformat prefix.
3786bff719fSBram Moolenaar  */
379de3b3677SBram Moolenaar     static char_u *
efm_analyze_prefix(char_u * efmp,efm_T * efminfo)380f9e3e09fSBram Moolenaar efm_analyze_prefix(char_u *efmp, efm_T *efminfo)
381071d4279SBram Moolenaar {
382071d4279SBram Moolenaar     if (vim_strchr((char_u *)"+-", *efmp) != NULL)
383de3b3677SBram Moolenaar 	efminfo->flags = *efmp++;
384e928366dSBram Moolenaar     if (vim_strchr((char_u *)"DXAEWINCZGOPQ", *efmp) != NULL)
385de3b3677SBram Moolenaar 	efminfo->prefix = *efmp;
386071d4279SBram Moolenaar     else
387071d4279SBram Moolenaar     {
388f9e3e09fSBram Moolenaar 	semsg(_("E376: Invalid %%%c in format string prefix"), *efmp);
389de3b3677SBram Moolenaar 	return NULL;
3906bff719fSBram Moolenaar     }
3916bff719fSBram Moolenaar 
392de3b3677SBram Moolenaar     return efmp;
3936bff719fSBram Moolenaar }
3946bff719fSBram Moolenaar 
3956bff719fSBram Moolenaar /*
396de3b3677SBram Moolenaar  * Converts a 'errorformat' string part in 'efm' to a regular expression
397de3b3677SBram Moolenaar  * pattern.  The resulting regex pattern is returned in "regpat". Additional
398de3b3677SBram Moolenaar  * information about the 'erroformat' pattern is returned in "fmt_ptr".
399de3b3677SBram Moolenaar  * Returns OK or FAIL.
4006bff719fSBram Moolenaar  */
4016bff719fSBram Moolenaar     static int
efm_to_regpat(char_u * efm,int len,efm_T * fmt_ptr,char_u * regpat)4026bff719fSBram Moolenaar efm_to_regpat(
4036bff719fSBram Moolenaar 	char_u	*efm,
4046bff719fSBram Moolenaar 	int	len,
4056bff719fSBram Moolenaar 	efm_T	*fmt_ptr,
406f9e3e09fSBram Moolenaar 	char_u	*regpat)
4076bff719fSBram Moolenaar {
4086bff719fSBram Moolenaar     char_u	*ptr;
4096bff719fSBram Moolenaar     char_u	*efmp;
4106bff719fSBram Moolenaar     int		round;
4116bff719fSBram Moolenaar     int		idx = 0;
4126bff719fSBram Moolenaar 
41300bf8cd2SBram Moolenaar     // Build a regexp pattern for a 'errorformat' option part
4146bff719fSBram Moolenaar     ptr = regpat;
4156bff719fSBram Moolenaar     *ptr++ = '^';
4166bff719fSBram Moolenaar     round = 0;
4176bff719fSBram Moolenaar     for (efmp = efm; efmp < efm + len; ++efmp)
4186bff719fSBram Moolenaar     {
4196bff719fSBram Moolenaar 	if (*efmp == '%')
4206bff719fSBram Moolenaar 	{
4216bff719fSBram Moolenaar 	    ++efmp;
4226bff719fSBram Moolenaar 	    for (idx = 0; idx < FMT_PATTERNS; ++idx)
4236bff719fSBram Moolenaar 		if (fmt_pat[idx].convchar == *efmp)
4246bff719fSBram Moolenaar 		    break;
4256bff719fSBram Moolenaar 	    if (idx < FMT_PATTERNS)
4266bff719fSBram Moolenaar 	    {
427f9e3e09fSBram Moolenaar 		ptr = efmpat_to_regpat(efmp, ptr, fmt_ptr, idx, round);
4286bff719fSBram Moolenaar 		if (ptr == NULL)
429de3b3677SBram Moolenaar 		    return FAIL;
4306bff719fSBram Moolenaar 		round++;
4316bff719fSBram Moolenaar 	    }
4326bff719fSBram Moolenaar 	    else if (*efmp == '*')
4336bff719fSBram Moolenaar 	    {
434de3b3677SBram Moolenaar 		++efmp;
435f9e3e09fSBram Moolenaar 		ptr = scanf_fmt_to_regpat(&efmp, efm, len, ptr);
4366bff719fSBram Moolenaar 		if (ptr == NULL)
437de3b3677SBram Moolenaar 		    return FAIL;
438071d4279SBram Moolenaar 	    }
4396bff719fSBram Moolenaar 	    else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL)
44000bf8cd2SBram Moolenaar 		*ptr++ = *efmp;		// regexp magic characters
4416bff719fSBram Moolenaar 	    else if (*efmp == '#')
4426bff719fSBram Moolenaar 		*ptr++ = '*';
4436bff719fSBram Moolenaar 	    else if (*efmp == '>')
4446bff719fSBram Moolenaar 		fmt_ptr->conthere = TRUE;
44500bf8cd2SBram Moolenaar 	    else if (efmp == efm + 1)		// analyse prefix
4466bff719fSBram Moolenaar 	    {
44700bf8cd2SBram Moolenaar 		// prefix is allowed only at the beginning of the errorformat
44800bf8cd2SBram Moolenaar 		// option part
449f9e3e09fSBram Moolenaar 		efmp = efm_analyze_prefix(efmp, fmt_ptr);
450de3b3677SBram Moolenaar 		if (efmp == NULL)
451de3b3677SBram Moolenaar 		    return FAIL;
452071d4279SBram Moolenaar 	    }
453071d4279SBram Moolenaar 	    else
454071d4279SBram Moolenaar 	    {
455f9e3e09fSBram Moolenaar 		semsg(_("E377: Invalid %%%c in format string"), *efmp);
456de3b3677SBram Moolenaar 		return FAIL;
457071d4279SBram Moolenaar 	    }
458071d4279SBram Moolenaar 	}
45900bf8cd2SBram Moolenaar 	else			// copy normal character
460071d4279SBram Moolenaar 	{
461071d4279SBram Moolenaar 	    if (*efmp == '\\' && efmp + 1 < efm + len)
462071d4279SBram Moolenaar 		++efmp;
463071d4279SBram Moolenaar 	    else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL)
46400bf8cd2SBram Moolenaar 		*ptr++ = '\\';	// escape regexp atoms
465071d4279SBram Moolenaar 	    if (*efmp)
466071d4279SBram Moolenaar 		*ptr++ = *efmp;
467071d4279SBram Moolenaar 	}
468071d4279SBram Moolenaar     }
469071d4279SBram Moolenaar     *ptr++ = '$';
470071d4279SBram Moolenaar     *ptr = NUL;
471688e3d1fSBram Moolenaar 
472de3b3677SBram Moolenaar     return OK;
473688e3d1fSBram Moolenaar }
474688e3d1fSBram Moolenaar 
475de3b3677SBram Moolenaar /*
476de3b3677SBram Moolenaar  * Free the 'errorformat' information list
477de3b3677SBram Moolenaar  */
478688e3d1fSBram Moolenaar     static void
free_efm_list(efm_T ** efm_first)479688e3d1fSBram Moolenaar free_efm_list(efm_T **efm_first)
480688e3d1fSBram Moolenaar {
481688e3d1fSBram Moolenaar     efm_T *efm_ptr;
482688e3d1fSBram Moolenaar 
483688e3d1fSBram Moolenaar     for (efm_ptr = *efm_first; efm_ptr != NULL; efm_ptr = *efm_first)
484688e3d1fSBram Moolenaar     {
485688e3d1fSBram Moolenaar 	*efm_first = efm_ptr->next;
486688e3d1fSBram Moolenaar 	vim_regfree(efm_ptr->prog);
487688e3d1fSBram Moolenaar 	vim_free(efm_ptr);
488688e3d1fSBram Moolenaar     }
48963bed3d3SBram Moolenaar     fmt_start = NULL;
490688e3d1fSBram Moolenaar }
491688e3d1fSBram Moolenaar 
492de3b3677SBram Moolenaar /*
493de3b3677SBram Moolenaar  * Compute the size of the buffer used to convert a 'errorformat' pattern into
494de3b3677SBram Moolenaar  * a regular expression pattern.
495de3b3677SBram Moolenaar  */
496de3b3677SBram Moolenaar     static int
efm_regpat_bufsz(char_u * efm)497de3b3677SBram Moolenaar efm_regpat_bufsz(char_u *efm)
498de3b3677SBram Moolenaar {
499de3b3677SBram Moolenaar     int sz;
500de3b3677SBram Moolenaar     int i;
501de3b3677SBram Moolenaar 
502de3b3677SBram Moolenaar     sz = (FMT_PATTERNS * 3) + ((int)STRLEN(efm) << 2);
503de3b3677SBram Moolenaar     for (i = FMT_PATTERNS; i > 0; )
504de3b3677SBram Moolenaar 	sz += (int)STRLEN(fmt_pat[--i].pattern);
505de3b3677SBram Moolenaar #ifdef BACKSLASH_IN_FILENAME
50600bf8cd2SBram Moolenaar     sz += 12; // "%f" can become twelve chars longer (see efm_to_regpat)
507de3b3677SBram Moolenaar #else
50800bf8cd2SBram Moolenaar     sz += 2; // "%f" can become two chars longer
509de3b3677SBram Moolenaar #endif
510de3b3677SBram Moolenaar 
511de3b3677SBram Moolenaar     return sz;
512de3b3677SBram Moolenaar }
513de3b3677SBram Moolenaar 
514de3b3677SBram Moolenaar /*
515de3b3677SBram Moolenaar  * Return the length of a 'errorformat' option part (separated by ",").
516de3b3677SBram Moolenaar  */
517de3b3677SBram Moolenaar     static int
efm_option_part_len(char_u * efm)518de3b3677SBram Moolenaar efm_option_part_len(char_u *efm)
519de3b3677SBram Moolenaar {
520de3b3677SBram Moolenaar     int len;
521de3b3677SBram Moolenaar 
522de3b3677SBram Moolenaar     for (len = 0; efm[len] != NUL && efm[len] != ','; ++len)
523de3b3677SBram Moolenaar 	if (efm[len] == '\\' && efm[len + 1] != NUL)
524de3b3677SBram Moolenaar 	    ++len;
525de3b3677SBram Moolenaar 
526de3b3677SBram Moolenaar     return len;
527de3b3677SBram Moolenaar }
528de3b3677SBram Moolenaar 
529de3b3677SBram Moolenaar /*
530de3b3677SBram Moolenaar  * Parse the 'errorformat' option. Multiple parts in the 'errorformat' option
531de3b3677SBram Moolenaar  * are parsed and converted to regular expressions. Returns information about
532de3b3677SBram Moolenaar  * the parsed 'errorformat' option.
533de3b3677SBram Moolenaar  */
534688e3d1fSBram Moolenaar     static efm_T *
parse_efm_option(char_u * efm)535688e3d1fSBram Moolenaar parse_efm_option(char_u *efm)
536688e3d1fSBram Moolenaar {
537688e3d1fSBram Moolenaar     efm_T	*fmt_ptr = NULL;
538688e3d1fSBram Moolenaar     efm_T	*fmt_first = NULL;
539688e3d1fSBram Moolenaar     efm_T	*fmt_last = NULL;
540688e3d1fSBram Moolenaar     char_u	*fmtstr = NULL;
541688e3d1fSBram Moolenaar     int		len;
542de3b3677SBram Moolenaar     int		sz;
543688e3d1fSBram Moolenaar 
54400bf8cd2SBram Moolenaar     // Each part of the format string is copied and modified from errorformat
54500bf8cd2SBram Moolenaar     // to regex prog.  Only a few % characters are allowed.
546e87e6dddSBram Moolenaar 
54700bf8cd2SBram Moolenaar     // Get some space to modify the format string into.
548de3b3677SBram Moolenaar     sz = efm_regpat_bufsz(efm);
549de3b3677SBram Moolenaar     if ((fmtstr = alloc(sz)) == NULL)
550688e3d1fSBram Moolenaar 	goto parse_efm_error;
551688e3d1fSBram Moolenaar 
552688e3d1fSBram Moolenaar     while (efm[0] != NUL)
553688e3d1fSBram Moolenaar     {
55400bf8cd2SBram Moolenaar 	// Allocate a new eformat structure and put it at the end of the list
555c799fe20SBram Moolenaar 	fmt_ptr = ALLOC_CLEAR_ONE(efm_T);
556688e3d1fSBram Moolenaar 	if (fmt_ptr == NULL)
557688e3d1fSBram Moolenaar 	    goto parse_efm_error;
55800bf8cd2SBram Moolenaar 	if (fmt_first == NULL)	    // first one
559688e3d1fSBram Moolenaar 	    fmt_first = fmt_ptr;
560688e3d1fSBram Moolenaar 	else
561688e3d1fSBram Moolenaar 	    fmt_last->next = fmt_ptr;
562688e3d1fSBram Moolenaar 	fmt_last = fmt_ptr;
563688e3d1fSBram Moolenaar 
56400bf8cd2SBram Moolenaar 	// Isolate one part in the 'errorformat' option
565de3b3677SBram Moolenaar 	len = efm_option_part_len(efm);
566688e3d1fSBram Moolenaar 
567f9e3e09fSBram Moolenaar 	if (efm_to_regpat(efm, len, fmt_ptr, fmtstr) == FAIL)
568688e3d1fSBram Moolenaar 	    goto parse_efm_error;
569071d4279SBram Moolenaar 	if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL)
570688e3d1fSBram Moolenaar 	    goto parse_efm_error;
57100bf8cd2SBram Moolenaar 	// Advance to next part
57200bf8cd2SBram Moolenaar 	efm = skip_to_option_part(efm + len);	// skip comma and spaces
573071d4279SBram Moolenaar     }
574688e3d1fSBram Moolenaar 
57500bf8cd2SBram Moolenaar     if (fmt_first == NULL)	// nothing found
576f9e3e09fSBram Moolenaar 	emsg(_("E378: 'errorformat' contains no pattern"));
577688e3d1fSBram Moolenaar 
578688e3d1fSBram Moolenaar     goto parse_efm_end;
579688e3d1fSBram Moolenaar 
580688e3d1fSBram Moolenaar parse_efm_error:
581688e3d1fSBram Moolenaar     free_efm_list(&fmt_first);
582688e3d1fSBram Moolenaar 
583688e3d1fSBram Moolenaar parse_efm_end:
584688e3d1fSBram Moolenaar     vim_free(fmtstr);
585688e3d1fSBram Moolenaar 
586688e3d1fSBram Moolenaar     return fmt_first;
587071d4279SBram Moolenaar }
588071d4279SBram Moolenaar 
589e0d37976SBram Moolenaar enum {
590e0d37976SBram Moolenaar     QF_FAIL = 0,
591e0d37976SBram Moolenaar     QF_OK = 1,
592e0d37976SBram Moolenaar     QF_END_OF_INPUT = 2,
593e87e6dddSBram Moolenaar     QF_NOMEM = 3,
59418cebf44SBram Moolenaar     QF_IGNORE_LINE = 4,
59518cebf44SBram Moolenaar     QF_MULTISCAN = 5,
596e0d37976SBram Moolenaar };
597e0d37976SBram Moolenaar 
598de3b3677SBram Moolenaar /*
599de3b3677SBram Moolenaar  * State information used to parse lines and add entries to a quickfix/location
600de3b3677SBram Moolenaar  * list.
601de3b3677SBram Moolenaar  */
602e0d37976SBram Moolenaar typedef struct {
603e0d37976SBram Moolenaar     char_u	*linebuf;
604e0d37976SBram Moolenaar     int		linelen;
605e0d37976SBram Moolenaar     char_u	*growbuf;
606e0d37976SBram Moolenaar     int		growbufsiz;
607e0d37976SBram Moolenaar     FILE	*fd;
608e0d37976SBram Moolenaar     typval_T	*tv;
609e0d37976SBram Moolenaar     char_u	*p_str;
610e0d37976SBram Moolenaar     listitem_T	*p_li;
611e0d37976SBram Moolenaar     buf_T	*buf;
612e0d37976SBram Moolenaar     linenr_T	buflnum;
613e0d37976SBram Moolenaar     linenr_T	lnumlast;
6142c7292dcSBram Moolenaar     vimconv_T	vc;
615e0d37976SBram Moolenaar } qfstate_T;
616e0d37976SBram Moolenaar 
617de3b3677SBram Moolenaar /*
618de3b3677SBram Moolenaar  * Allocate more memory for the line buffer used for parsing lines.
619de3b3677SBram Moolenaar  */
620e0d37976SBram Moolenaar     static char_u *
qf_grow_linebuf(qfstate_T * state,int newsz)621e0d37976SBram Moolenaar qf_grow_linebuf(qfstate_T *state, int newsz)
622e0d37976SBram Moolenaar {
62318cebf44SBram Moolenaar     char_u	*p;
62418cebf44SBram Moolenaar 
62500bf8cd2SBram Moolenaar     // If the line exceeds LINE_MAXLEN exclude the last
62600bf8cd2SBram Moolenaar     // byte since it's not a NL character.
627e0d37976SBram Moolenaar     state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz;
628e0d37976SBram Moolenaar     if (state->growbuf == NULL)
629e0d37976SBram Moolenaar     {
630e0d37976SBram Moolenaar 	state->growbuf = alloc(state->linelen + 1);
631e0d37976SBram Moolenaar 	if (state->growbuf == NULL)
632e0d37976SBram Moolenaar 	    return NULL;
633e0d37976SBram Moolenaar 	state->growbufsiz = state->linelen;
634e0d37976SBram Moolenaar     }
635e0d37976SBram Moolenaar     else if (state->linelen > state->growbufsiz)
636e0d37976SBram Moolenaar     {
63718cebf44SBram Moolenaar 	if ((p = vim_realloc(state->growbuf, state->linelen + 1)) == NULL)
638e0d37976SBram Moolenaar 	    return NULL;
63918cebf44SBram Moolenaar 	state->growbuf = p;
640e0d37976SBram Moolenaar 	state->growbufsiz = state->linelen;
641e0d37976SBram Moolenaar     }
642e0d37976SBram Moolenaar     return state->growbuf;
643e0d37976SBram Moolenaar }
644e0d37976SBram Moolenaar 
645e0d37976SBram Moolenaar /*
646e0d37976SBram Moolenaar  * Get the next string (separated by newline) from state->p_str.
647e0d37976SBram Moolenaar  */
648e0d37976SBram Moolenaar     static int
qf_get_next_str_line(qfstate_T * state)649e0d37976SBram Moolenaar qf_get_next_str_line(qfstate_T *state)
650e0d37976SBram Moolenaar {
65100bf8cd2SBram Moolenaar     // Get the next line from the supplied string
652e0d37976SBram Moolenaar     char_u	*p_str = state->p_str;
653e0d37976SBram Moolenaar     char_u	*p;
654e0d37976SBram Moolenaar     int		len;
655e0d37976SBram Moolenaar 
65600bf8cd2SBram Moolenaar     if (*p_str == NUL) // Reached the end of the string
657e0d37976SBram Moolenaar 	return QF_END_OF_INPUT;
658e0d37976SBram Moolenaar 
659e0d37976SBram Moolenaar     p = vim_strchr(p_str, '\n');
660e0d37976SBram Moolenaar     if (p != NULL)
661e0d37976SBram Moolenaar 	len = (int)(p - p_str) + 1;
662e0d37976SBram Moolenaar     else
663e0d37976SBram Moolenaar 	len = (int)STRLEN(p_str);
664e0d37976SBram Moolenaar 
665e0d37976SBram Moolenaar     if (len > IOSIZE - 2)
666e0d37976SBram Moolenaar     {
667e0d37976SBram Moolenaar 	state->linebuf = qf_grow_linebuf(state, len);
668e0d37976SBram Moolenaar 	if (state->linebuf == NULL)
669e0d37976SBram Moolenaar 	    return QF_NOMEM;
670e0d37976SBram Moolenaar     }
671e0d37976SBram Moolenaar     else
672e0d37976SBram Moolenaar     {
673e0d37976SBram Moolenaar 	state->linebuf = IObuff;
674e0d37976SBram Moolenaar 	state->linelen = len;
675e0d37976SBram Moolenaar     }
676e0d37976SBram Moolenaar     vim_strncpy(state->linebuf, p_str, state->linelen);
677e0d37976SBram Moolenaar 
67800bf8cd2SBram Moolenaar     // Increment using len in order to discard the rest of the
67900bf8cd2SBram Moolenaar     // line if it exceeds LINE_MAXLEN.
680e0d37976SBram Moolenaar     p_str += len;
681e0d37976SBram Moolenaar     state->p_str = p_str;
682e0d37976SBram Moolenaar 
683e0d37976SBram Moolenaar     return QF_OK;
684e0d37976SBram Moolenaar }
685e0d37976SBram Moolenaar 
686e0d37976SBram Moolenaar /*
687e0d37976SBram Moolenaar  * Get the next string from state->p_Li.
688e0d37976SBram Moolenaar  */
689e0d37976SBram Moolenaar     static int
qf_get_next_list_line(qfstate_T * state)690e0d37976SBram Moolenaar qf_get_next_list_line(qfstate_T *state)
691e0d37976SBram Moolenaar {
692e0d37976SBram Moolenaar     listitem_T	*p_li = state->p_li;
693e0d37976SBram Moolenaar     int		len;
694e0d37976SBram Moolenaar 
695e0d37976SBram Moolenaar     while (p_li != NULL
696e0d37976SBram Moolenaar 	    && (p_li->li_tv.v_type != VAR_STRING
697e0d37976SBram Moolenaar 		|| p_li->li_tv.vval.v_string == NULL))
69800bf8cd2SBram Moolenaar 	p_li = p_li->li_next;	// Skip non-string items
699e0d37976SBram Moolenaar 
70000bf8cd2SBram Moolenaar     if (p_li == NULL)		// End of the list
701e0d37976SBram Moolenaar     {
702e0d37976SBram Moolenaar 	state->p_li = NULL;
703e0d37976SBram Moolenaar 	return QF_END_OF_INPUT;
704e0d37976SBram Moolenaar     }
705e0d37976SBram Moolenaar 
706e0d37976SBram Moolenaar     len = (int)STRLEN(p_li->li_tv.vval.v_string);
707e0d37976SBram Moolenaar     if (len > IOSIZE - 2)
708e0d37976SBram Moolenaar     {
709e0d37976SBram Moolenaar 	state->linebuf = qf_grow_linebuf(state, len);
710e0d37976SBram Moolenaar 	if (state->linebuf == NULL)
711e0d37976SBram Moolenaar 	    return QF_NOMEM;
712e0d37976SBram Moolenaar     }
713e0d37976SBram Moolenaar     else
714e0d37976SBram Moolenaar     {
715e0d37976SBram Moolenaar 	state->linebuf = IObuff;
716e0d37976SBram Moolenaar 	state->linelen = len;
717e0d37976SBram Moolenaar     }
718e0d37976SBram Moolenaar 
719e0d37976SBram Moolenaar     vim_strncpy(state->linebuf, p_li->li_tv.vval.v_string, state->linelen);
720e0d37976SBram Moolenaar 
72100bf8cd2SBram Moolenaar     state->p_li = p_li->li_next;	// next item
722e0d37976SBram Moolenaar     return QF_OK;
723e0d37976SBram Moolenaar }
724e0d37976SBram Moolenaar 
725e0d37976SBram Moolenaar /*
726e0d37976SBram Moolenaar  * Get the next string from state->buf.
727e0d37976SBram Moolenaar  */
728e0d37976SBram Moolenaar     static int
qf_get_next_buf_line(qfstate_T * state)729e0d37976SBram Moolenaar qf_get_next_buf_line(qfstate_T *state)
730e0d37976SBram Moolenaar {
731e0d37976SBram Moolenaar     char_u	*p_buf = NULL;
732e0d37976SBram Moolenaar     int		len;
733e0d37976SBram Moolenaar 
73400bf8cd2SBram Moolenaar     // Get the next line from the supplied buffer
735e0d37976SBram Moolenaar     if (state->buflnum > state->lnumlast)
736e0d37976SBram Moolenaar 	return QF_END_OF_INPUT;
737e0d37976SBram Moolenaar 
738e0d37976SBram Moolenaar     p_buf = ml_get_buf(state->buf, state->buflnum, FALSE);
739e0d37976SBram Moolenaar     state->buflnum += 1;
740e0d37976SBram Moolenaar 
741e0d37976SBram Moolenaar     len = (int)STRLEN(p_buf);
742e0d37976SBram Moolenaar     if (len > IOSIZE - 2)
743e0d37976SBram Moolenaar     {
744e0d37976SBram Moolenaar 	state->linebuf = qf_grow_linebuf(state, len);
745e0d37976SBram Moolenaar 	if (state->linebuf == NULL)
746e0d37976SBram Moolenaar 	    return QF_NOMEM;
747e0d37976SBram Moolenaar     }
748e0d37976SBram Moolenaar     else
749e0d37976SBram Moolenaar     {
750e0d37976SBram Moolenaar 	state->linebuf = IObuff;
751e0d37976SBram Moolenaar 	state->linelen = len;
752e0d37976SBram Moolenaar     }
753e0d37976SBram Moolenaar     vim_strncpy(state->linebuf, p_buf, state->linelen);
754e0d37976SBram Moolenaar 
755e0d37976SBram Moolenaar     return QF_OK;
756e0d37976SBram Moolenaar }
757e0d37976SBram Moolenaar 
758e0d37976SBram Moolenaar /*
759e0d37976SBram Moolenaar  * Get the next string from file state->fd.
760e0d37976SBram Moolenaar  */
761e0d37976SBram Moolenaar     static int
qf_get_next_file_line(qfstate_T * state)762e0d37976SBram Moolenaar qf_get_next_file_line(qfstate_T *state)
763e0d37976SBram Moolenaar {
764e0d37976SBram Moolenaar     int	    discard;
765e0d37976SBram Moolenaar     int	    growbuflen;
766e0d37976SBram Moolenaar 
767e0d37976SBram Moolenaar     if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL)
768e0d37976SBram Moolenaar 	return QF_END_OF_INPUT;
769e0d37976SBram Moolenaar 
770e0d37976SBram Moolenaar     discard = FALSE;
771e0d37976SBram Moolenaar     state->linelen = (int)STRLEN(IObuff);
772796aa9c8SBram Moolenaar     if (state->linelen == IOSIZE - 1 && !(IObuff[state->linelen - 1] == '\n'))
773e0d37976SBram Moolenaar     {
77400bf8cd2SBram Moolenaar 	// The current line exceeds IObuff, continue reading using
77500bf8cd2SBram Moolenaar 	// growbuf until EOL or LINE_MAXLEN bytes is read.
776e0d37976SBram Moolenaar 	if (state->growbuf == NULL)
777e0d37976SBram Moolenaar 	{
778e0d37976SBram Moolenaar 	    state->growbufsiz = 2 * (IOSIZE - 1);
779e0d37976SBram Moolenaar 	    state->growbuf = alloc(state->growbufsiz);
780e0d37976SBram Moolenaar 	    if (state->growbuf == NULL)
781e0d37976SBram Moolenaar 		return QF_NOMEM;
782e0d37976SBram Moolenaar 	}
783e0d37976SBram Moolenaar 
78400bf8cd2SBram Moolenaar 	// Copy the read part of the line, excluding null-terminator
785e0d37976SBram Moolenaar 	memcpy(state->growbuf, IObuff, IOSIZE - 1);
786e0d37976SBram Moolenaar 	growbuflen = state->linelen;
787e0d37976SBram Moolenaar 
788e0d37976SBram Moolenaar 	for (;;)
789e0d37976SBram Moolenaar 	{
79018cebf44SBram Moolenaar 	    char_u	*p;
79118cebf44SBram Moolenaar 
792e0d37976SBram Moolenaar 	    if (fgets((char *)state->growbuf + growbuflen,
793e0d37976SBram Moolenaar 			state->growbufsiz - growbuflen, state->fd) == NULL)
794e0d37976SBram Moolenaar 		break;
795e0d37976SBram Moolenaar 	    state->linelen = (int)STRLEN(state->growbuf + growbuflen);
796e0d37976SBram Moolenaar 	    growbuflen += state->linelen;
797796aa9c8SBram Moolenaar 	    if ((state->growbuf)[growbuflen - 1] == '\n')
798e0d37976SBram Moolenaar 		break;
799e0d37976SBram Moolenaar 	    if (state->growbufsiz == LINE_MAXLEN)
800e0d37976SBram Moolenaar 	    {
801e0d37976SBram Moolenaar 		discard = TRUE;
802e0d37976SBram Moolenaar 		break;
803e0d37976SBram Moolenaar 	    }
804e0d37976SBram Moolenaar 
805e0d37976SBram Moolenaar 	    state->growbufsiz = 2 * state->growbufsiz < LINE_MAXLEN
806e0d37976SBram Moolenaar 		? 2 * state->growbufsiz : LINE_MAXLEN;
80718cebf44SBram Moolenaar 	    if ((p = vim_realloc(state->growbuf, state->growbufsiz)) == NULL)
808e0d37976SBram Moolenaar 		return QF_NOMEM;
80918cebf44SBram Moolenaar 	    state->growbuf = p;
810e0d37976SBram Moolenaar 	}
811e0d37976SBram Moolenaar 
812e0d37976SBram Moolenaar 	while (discard)
813e0d37976SBram Moolenaar 	{
81400bf8cd2SBram Moolenaar 	    // The current line is longer than LINE_MAXLEN, continue
81500bf8cd2SBram Moolenaar 	    // reading but discard everything until EOL or EOF is
81600bf8cd2SBram Moolenaar 	    // reached.
817e0d37976SBram Moolenaar 	    if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL
818e0d37976SBram Moolenaar 		    || (int)STRLEN(IObuff) < IOSIZE - 1
81959941cbdSBram Moolenaar 		    || IObuff[IOSIZE - 2] == '\n')
820e0d37976SBram Moolenaar 		break;
821e0d37976SBram Moolenaar 	}
822e0d37976SBram Moolenaar 
823e0d37976SBram Moolenaar 	state->linebuf = state->growbuf;
824e0d37976SBram Moolenaar 	state->linelen = growbuflen;
825e0d37976SBram Moolenaar     }
826e0d37976SBram Moolenaar     else
827e0d37976SBram Moolenaar 	state->linebuf = IObuff;
828e0d37976SBram Moolenaar 
82900bf8cd2SBram Moolenaar     // Convert a line if it contains a non-ASCII character.
830b6fa30ccSBram Moolenaar     if (state->vc.vc_type != CONV_NONE && has_non_ascii(state->linebuf))
831b6fa30ccSBram Moolenaar     {
8322c7292dcSBram Moolenaar 	char_u	*line;
8332c7292dcSBram Moolenaar 
8342c7292dcSBram Moolenaar 	line = string_convert(&state->vc, state->linebuf, &state->linelen);
8352c7292dcSBram Moolenaar 	if (line != NULL)
8362c7292dcSBram Moolenaar 	{
8372c7292dcSBram Moolenaar 	    if (state->linelen < IOSIZE)
8382c7292dcSBram Moolenaar 	    {
8392c7292dcSBram Moolenaar 		STRCPY(state->linebuf, line);
8402c7292dcSBram Moolenaar 		vim_free(line);
8412c7292dcSBram Moolenaar 	    }
8422c7292dcSBram Moolenaar 	    else
8432c7292dcSBram Moolenaar 	    {
8442c7292dcSBram Moolenaar 		vim_free(state->growbuf);
8452c7292dcSBram Moolenaar 		state->linebuf = state->growbuf = line;
8462c7292dcSBram Moolenaar 		state->growbufsiz = state->linelen < LINE_MAXLEN
8472c7292dcSBram Moolenaar 						? state->linelen : LINE_MAXLEN;
8482c7292dcSBram Moolenaar 	    }
8492c7292dcSBram Moolenaar 	}
8502c7292dcSBram Moolenaar     }
8512c7292dcSBram Moolenaar 
852e0d37976SBram Moolenaar     return QF_OK;
853e0d37976SBram Moolenaar }
854e0d37976SBram Moolenaar 
855e0d37976SBram Moolenaar /*
856e0d37976SBram Moolenaar  * Get the next string from a file/buffer/list/string.
857e0d37976SBram Moolenaar  */
858e0d37976SBram Moolenaar     static int
qf_get_nextline(qfstate_T * state)859e0d37976SBram Moolenaar qf_get_nextline(qfstate_T *state)
860e0d37976SBram Moolenaar {
861e0d37976SBram Moolenaar     int status = QF_FAIL;
862e0d37976SBram Moolenaar 
863e0d37976SBram Moolenaar     if (state->fd == NULL)
864e0d37976SBram Moolenaar     {
865e0d37976SBram Moolenaar 	if (state->tv != NULL)
866e0d37976SBram Moolenaar 	{
867e0d37976SBram Moolenaar 	    if (state->tv->v_type == VAR_STRING)
86800bf8cd2SBram Moolenaar 		// Get the next line from the supplied string
869e0d37976SBram Moolenaar 		status = qf_get_next_str_line(state);
870e0d37976SBram Moolenaar 	    else if (state->tv->v_type == VAR_LIST)
87100bf8cd2SBram Moolenaar 		// Get the next line from the supplied list
872e0d37976SBram Moolenaar 		status = qf_get_next_list_line(state);
873e0d37976SBram Moolenaar 	}
874e0d37976SBram Moolenaar 	else
87500bf8cd2SBram Moolenaar 	    // Get the next line from the supplied buffer
876e0d37976SBram Moolenaar 	    status = qf_get_next_buf_line(state);
877e0d37976SBram Moolenaar     }
878e0d37976SBram Moolenaar     else
87900bf8cd2SBram Moolenaar 	// Get the next line from the supplied file
880e0d37976SBram Moolenaar 	status = qf_get_next_file_line(state);
881e0d37976SBram Moolenaar 
882e0d37976SBram Moolenaar     if (status != QF_OK)
883e0d37976SBram Moolenaar 	return status;
884e0d37976SBram Moolenaar 
88500bf8cd2SBram Moolenaar     // remove newline/CR from the line
886e0d37976SBram Moolenaar     if (state->linelen > 0 && state->linebuf[state->linelen - 1] == '\n')
887796aa9c8SBram Moolenaar     {
888e0d37976SBram Moolenaar 	state->linebuf[state->linelen - 1] = NUL;
889e0d37976SBram Moolenaar #ifdef USE_CRNL
890796aa9c8SBram Moolenaar 	if (state->linelen > 1 && state->linebuf[state->linelen - 2] == '\r')
891796aa9c8SBram Moolenaar 	    state->linebuf[state->linelen - 2] = NUL;
892e0d37976SBram Moolenaar #endif
893796aa9c8SBram Moolenaar     }
894e0d37976SBram Moolenaar 
895e0d37976SBram Moolenaar     remove_bom(state->linebuf);
896e0d37976SBram Moolenaar 
897e0d37976SBram Moolenaar     return QF_OK;
898e0d37976SBram Moolenaar }
899e0d37976SBram Moolenaar 
900e87e6dddSBram Moolenaar typedef struct {
901e87e6dddSBram Moolenaar     char_u	*namebuf;
902d76ce852SBram Moolenaar     char_u	*module;
903e87e6dddSBram Moolenaar     char_u	*errmsg;
904e87e6dddSBram Moolenaar     int		errmsglen;
905e87e6dddSBram Moolenaar     long	lnum;
9066864efa5Sthinca     long	end_lnum;
907e87e6dddSBram Moolenaar     int		col;
9086864efa5Sthinca     int		end_col;
909e87e6dddSBram Moolenaar     char_u	use_viscol;
910e87e6dddSBram Moolenaar     char_u	*pattern;
911e87e6dddSBram Moolenaar     int		enr;
912e87e6dddSBram Moolenaar     int		type;
913e87e6dddSBram Moolenaar     int		valid;
914e87e6dddSBram Moolenaar } qffields_T;
915e87e6dddSBram Moolenaar 
916e87e6dddSBram Moolenaar /*
917de3b3677SBram Moolenaar  * Parse the match for filename ('%f') pattern in regmatch.
918de3b3677SBram Moolenaar  * Return the matched value in "fields->namebuf".
919de3b3677SBram Moolenaar  */
920de3b3677SBram Moolenaar     static int
qf_parse_fmt_f(regmatch_T * rmp,int midx,qffields_T * fields,int prefix)921de3b3677SBram Moolenaar qf_parse_fmt_f(regmatch_T *rmp, int midx, qffields_T *fields, int prefix)
922de3b3677SBram Moolenaar {
923de3b3677SBram Moolenaar     int c;
924de3b3677SBram Moolenaar 
925de3b3677SBram Moolenaar     if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
926de3b3677SBram Moolenaar 	return QF_FAIL;
927de3b3677SBram Moolenaar 
92800bf8cd2SBram Moolenaar     // Expand ~/file and $HOME/file to full path.
929de3b3677SBram Moolenaar     c = *rmp->endp[midx];
930de3b3677SBram Moolenaar     *rmp->endp[midx] = NUL;
931de3b3677SBram Moolenaar     expand_env(rmp->startp[midx], fields->namebuf, CMDBUFFSIZE);
932de3b3677SBram Moolenaar     *rmp->endp[midx] = c;
933de3b3677SBram Moolenaar 
93400bf8cd2SBram Moolenaar     // For separate filename patterns (%O, %P and %Q), the specified file
93500bf8cd2SBram Moolenaar     // should exist.
936de3b3677SBram Moolenaar     if (vim_strchr((char_u *)"OPQ", prefix) != NULL
937de3b3677SBram Moolenaar 	    && mch_getperm(fields->namebuf) == -1)
938de3b3677SBram Moolenaar 	return QF_FAIL;
939de3b3677SBram Moolenaar 
940de3b3677SBram Moolenaar     return QF_OK;
941de3b3677SBram Moolenaar }
942de3b3677SBram Moolenaar 
943de3b3677SBram Moolenaar /*
944de3b3677SBram Moolenaar  * Parse the match for error number ('%n') pattern in regmatch.
945de3b3677SBram Moolenaar  * Return the matched value in "fields->enr".
946de3b3677SBram Moolenaar  */
947de3b3677SBram Moolenaar     static int
qf_parse_fmt_n(regmatch_T * rmp,int midx,qffields_T * fields)948de3b3677SBram Moolenaar qf_parse_fmt_n(regmatch_T *rmp, int midx, qffields_T *fields)
949de3b3677SBram Moolenaar {
950de3b3677SBram Moolenaar     if (rmp->startp[midx] == NULL)
951de3b3677SBram Moolenaar 	return QF_FAIL;
952de3b3677SBram Moolenaar     fields->enr = (int)atol((char *)rmp->startp[midx]);
953de3b3677SBram Moolenaar     return QF_OK;
954de3b3677SBram Moolenaar }
955de3b3677SBram Moolenaar 
956de3b3677SBram Moolenaar /*
957de3b3677SBram Moolenaar  * Parse the match for line number (%l') pattern in regmatch.
958de3b3677SBram Moolenaar  * Return the matched value in "fields->lnum".
959de3b3677SBram Moolenaar  */
960de3b3677SBram Moolenaar     static int
qf_parse_fmt_l(regmatch_T * rmp,int midx,qffields_T * fields)961de3b3677SBram Moolenaar qf_parse_fmt_l(regmatch_T *rmp, int midx, qffields_T *fields)
962de3b3677SBram Moolenaar {
963de3b3677SBram Moolenaar     if (rmp->startp[midx] == NULL)
964de3b3677SBram Moolenaar 	return QF_FAIL;
965de3b3677SBram Moolenaar     fields->lnum = atol((char *)rmp->startp[midx]);
966de3b3677SBram Moolenaar     return QF_OK;
967de3b3677SBram Moolenaar }
968de3b3677SBram Moolenaar 
969de3b3677SBram Moolenaar /*
970de3b3677SBram Moolenaar  * Parse the match for column number ('%c') pattern in regmatch.
971de3b3677SBram Moolenaar  * Return the matched value in "fields->col".
972de3b3677SBram Moolenaar  */
973de3b3677SBram Moolenaar     static int
qf_parse_fmt_c(regmatch_T * rmp,int midx,qffields_T * fields)974de3b3677SBram Moolenaar qf_parse_fmt_c(regmatch_T *rmp, int midx, qffields_T *fields)
975de3b3677SBram Moolenaar {
976de3b3677SBram Moolenaar     if (rmp->startp[midx] == NULL)
977de3b3677SBram Moolenaar 	return QF_FAIL;
978de3b3677SBram Moolenaar     fields->col = (int)atol((char *)rmp->startp[midx]);
979de3b3677SBram Moolenaar     return QF_OK;
980de3b3677SBram Moolenaar }
981de3b3677SBram Moolenaar 
982de3b3677SBram Moolenaar /*
983de3b3677SBram Moolenaar  * Parse the match for error type ('%t') pattern in regmatch.
984de3b3677SBram Moolenaar  * Return the matched value in "fields->type".
985de3b3677SBram Moolenaar  */
986de3b3677SBram Moolenaar     static int
qf_parse_fmt_t(regmatch_T * rmp,int midx,qffields_T * fields)987de3b3677SBram Moolenaar qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields)
988de3b3677SBram Moolenaar {
989de3b3677SBram Moolenaar     if (rmp->startp[midx] == NULL)
990de3b3677SBram Moolenaar 	return QF_FAIL;
991de3b3677SBram Moolenaar     fields->type = *rmp->startp[midx];
992de3b3677SBram Moolenaar     return QF_OK;
993de3b3677SBram Moolenaar }
994de3b3677SBram Moolenaar 
995de3b3677SBram Moolenaar /*
996f4140488SBram Moolenaar  * Copy a non-error line into the error string.  Return the matched line in
997f4140488SBram Moolenaar  * "fields->errmsg".
998de3b3677SBram Moolenaar  */
999de3b3677SBram Moolenaar     static int
copy_nonerror_line(char_u * linebuf,int linelen,qffields_T * fields)1000f4140488SBram Moolenaar copy_nonerror_line(char_u *linebuf, int linelen, qffields_T *fields)
1001de3b3677SBram Moolenaar {
1002de3b3677SBram Moolenaar     char_u	*p;
1003de3b3677SBram Moolenaar 
1004de3b3677SBram Moolenaar     if (linelen >= fields->errmsglen)
1005de3b3677SBram Moolenaar     {
100600bf8cd2SBram Moolenaar 	// linelen + null terminator
1007de3b3677SBram Moolenaar 	if ((p = vim_realloc(fields->errmsg, linelen + 1)) == NULL)
1008de3b3677SBram Moolenaar 	    return QF_NOMEM;
1009de3b3677SBram Moolenaar 	fields->errmsg = p;
1010de3b3677SBram Moolenaar 	fields->errmsglen = linelen + 1;
1011de3b3677SBram Moolenaar     }
1012f4140488SBram Moolenaar     // copy whole line to error message
1013de3b3677SBram Moolenaar     vim_strncpy(fields->errmsg, linebuf, linelen);
1014f4140488SBram Moolenaar 
1015de3b3677SBram Moolenaar     return QF_OK;
1016de3b3677SBram Moolenaar }
1017de3b3677SBram Moolenaar 
1018de3b3677SBram Moolenaar /*
1019de3b3677SBram Moolenaar  * Parse the match for error message ('%m') pattern in regmatch.
1020de3b3677SBram Moolenaar  * Return the matched value in "fields->errmsg".
1021de3b3677SBram Moolenaar  */
1022de3b3677SBram Moolenaar     static int
qf_parse_fmt_m(regmatch_T * rmp,int midx,qffields_T * fields)1023de3b3677SBram Moolenaar qf_parse_fmt_m(regmatch_T *rmp, int midx, qffields_T *fields)
1024de3b3677SBram Moolenaar {
1025de3b3677SBram Moolenaar     char_u	*p;
1026de3b3677SBram Moolenaar     int		len;
1027de3b3677SBram Moolenaar 
1028de3b3677SBram Moolenaar     if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
1029de3b3677SBram Moolenaar 	return QF_FAIL;
1030de3b3677SBram Moolenaar     len = (int)(rmp->endp[midx] - rmp->startp[midx]);
1031de3b3677SBram Moolenaar     if (len >= fields->errmsglen)
1032de3b3677SBram Moolenaar     {
103300bf8cd2SBram Moolenaar 	// len + null terminator
1034de3b3677SBram Moolenaar 	if ((p = vim_realloc(fields->errmsg, len + 1)) == NULL)
1035de3b3677SBram Moolenaar 	    return QF_NOMEM;
1036de3b3677SBram Moolenaar 	fields->errmsg = p;
1037de3b3677SBram Moolenaar 	fields->errmsglen = len + 1;
1038de3b3677SBram Moolenaar     }
1039de3b3677SBram Moolenaar     vim_strncpy(fields->errmsg, rmp->startp[midx], len);
1040de3b3677SBram Moolenaar     return QF_OK;
1041de3b3677SBram Moolenaar }
1042de3b3677SBram Moolenaar 
1043de3b3677SBram Moolenaar /*
1044de3b3677SBram Moolenaar  * Parse the match for rest of a single-line file message ('%r') pattern.
1045de3b3677SBram Moolenaar  * Return the matched value in "tail".
1046de3b3677SBram Moolenaar  */
1047de3b3677SBram Moolenaar     static int
qf_parse_fmt_r(regmatch_T * rmp,int midx,char_u ** tail)1048de3b3677SBram Moolenaar qf_parse_fmt_r(regmatch_T *rmp, int midx, char_u **tail)
1049de3b3677SBram Moolenaar {
1050de3b3677SBram Moolenaar     if (rmp->startp[midx] == NULL)
1051de3b3677SBram Moolenaar 	return QF_FAIL;
1052de3b3677SBram Moolenaar     *tail = rmp->startp[midx];
1053de3b3677SBram Moolenaar     return QF_OK;
1054de3b3677SBram Moolenaar }
1055de3b3677SBram Moolenaar 
1056de3b3677SBram Moolenaar /*
1057de3b3677SBram Moolenaar  * Parse the match for the pointer line ('%p') pattern in regmatch.
1058de3b3677SBram Moolenaar  * Return the matched value in "fields->col".
1059de3b3677SBram Moolenaar  */
1060de3b3677SBram Moolenaar     static int
qf_parse_fmt_p(regmatch_T * rmp,int midx,qffields_T * fields)1061de3b3677SBram Moolenaar qf_parse_fmt_p(regmatch_T *rmp, int midx, qffields_T *fields)
1062de3b3677SBram Moolenaar {
1063de3b3677SBram Moolenaar     char_u	*match_ptr;
1064de3b3677SBram Moolenaar 
1065de3b3677SBram Moolenaar     if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
1066de3b3677SBram Moolenaar 	return QF_FAIL;
1067de3b3677SBram Moolenaar     fields->col = 0;
1068de3b3677SBram Moolenaar     for (match_ptr = rmp->startp[midx]; match_ptr != rmp->endp[midx];
1069de3b3677SBram Moolenaar 								++match_ptr)
1070de3b3677SBram Moolenaar     {
1071de3b3677SBram Moolenaar 	++fields->col;
1072de3b3677SBram Moolenaar 	if (*match_ptr == TAB)
1073de3b3677SBram Moolenaar 	{
1074de3b3677SBram Moolenaar 	    fields->col += 7;
1075de3b3677SBram Moolenaar 	    fields->col -= fields->col % 8;
1076de3b3677SBram Moolenaar 	}
1077de3b3677SBram Moolenaar     }
1078de3b3677SBram Moolenaar     ++fields->col;
1079de3b3677SBram Moolenaar     fields->use_viscol = TRUE;
1080de3b3677SBram Moolenaar     return QF_OK;
1081de3b3677SBram Moolenaar }
1082de3b3677SBram Moolenaar 
1083de3b3677SBram Moolenaar /*
1084de3b3677SBram Moolenaar  * Parse the match for the virtual column number ('%v') pattern in regmatch.
1085de3b3677SBram Moolenaar  * Return the matched value in "fields->col".
1086de3b3677SBram Moolenaar  */
1087de3b3677SBram Moolenaar     static int
qf_parse_fmt_v(regmatch_T * rmp,int midx,qffields_T * fields)1088de3b3677SBram Moolenaar qf_parse_fmt_v(regmatch_T *rmp, int midx, qffields_T *fields)
1089de3b3677SBram Moolenaar {
1090de3b3677SBram Moolenaar     if (rmp->startp[midx] == NULL)
1091de3b3677SBram Moolenaar 	return QF_FAIL;
1092de3b3677SBram Moolenaar     fields->col = (int)atol((char *)rmp->startp[midx]);
1093de3b3677SBram Moolenaar     fields->use_viscol = TRUE;
1094de3b3677SBram Moolenaar     return QF_OK;
1095de3b3677SBram Moolenaar }
1096de3b3677SBram Moolenaar 
1097de3b3677SBram Moolenaar /*
1098de3b3677SBram Moolenaar  * Parse the match for the search text ('%s') pattern in regmatch.
1099de3b3677SBram Moolenaar  * Return the matched value in "fields->pattern".
1100de3b3677SBram Moolenaar  */
1101de3b3677SBram Moolenaar     static int
qf_parse_fmt_s(regmatch_T * rmp,int midx,qffields_T * fields)1102de3b3677SBram Moolenaar qf_parse_fmt_s(regmatch_T *rmp, int midx, qffields_T *fields)
1103de3b3677SBram Moolenaar {
1104de3b3677SBram Moolenaar     int		len;
1105de3b3677SBram Moolenaar 
1106de3b3677SBram Moolenaar     if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
1107de3b3677SBram Moolenaar 	return QF_FAIL;
1108de3b3677SBram Moolenaar     len = (int)(rmp->endp[midx] - rmp->startp[midx]);
1109de3b3677SBram Moolenaar     if (len > CMDBUFFSIZE - 5)
1110de3b3677SBram Moolenaar 	len = CMDBUFFSIZE - 5;
1111de3b3677SBram Moolenaar     STRCPY(fields->pattern, "^\\V");
1112de3b3677SBram Moolenaar     STRNCAT(fields->pattern, rmp->startp[midx], len);
1113de3b3677SBram Moolenaar     fields->pattern[len + 3] = '\\';
1114de3b3677SBram Moolenaar     fields->pattern[len + 4] = '$';
1115de3b3677SBram Moolenaar     fields->pattern[len + 5] = NUL;
1116de3b3677SBram Moolenaar     return QF_OK;
1117de3b3677SBram Moolenaar }
1118de3b3677SBram Moolenaar 
1119de3b3677SBram Moolenaar /*
1120de3b3677SBram Moolenaar  * Parse the match for the module ('%o') pattern in regmatch.
1121de3b3677SBram Moolenaar  * Return the matched value in "fields->module".
1122de3b3677SBram Moolenaar  */
1123de3b3677SBram Moolenaar     static int
qf_parse_fmt_o(regmatch_T * rmp,int midx,qffields_T * fields)1124de3b3677SBram Moolenaar qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields)
1125de3b3677SBram Moolenaar {
1126de3b3677SBram Moolenaar     int		len;
1127de3b3677SBram Moolenaar 
1128de3b3677SBram Moolenaar     if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
1129de3b3677SBram Moolenaar 	return QF_FAIL;
1130de3b3677SBram Moolenaar     len = (int)(rmp->endp[midx] - rmp->startp[midx]);
1131de3b3677SBram Moolenaar     if (len > CMDBUFFSIZE)
1132de3b3677SBram Moolenaar 	len = CMDBUFFSIZE;
1133de3b3677SBram Moolenaar     STRNCAT(fields->module, rmp->startp[midx], len);
1134de3b3677SBram Moolenaar     return QF_OK;
1135de3b3677SBram Moolenaar }
1136de3b3677SBram Moolenaar 
1137de3b3677SBram Moolenaar /*
1138de3b3677SBram Moolenaar  * 'errorformat' format pattern parser functions.
1139de3b3677SBram Moolenaar  * The '%f' and '%r' formats are parsed differently from other formats.
1140de3b3677SBram Moolenaar  * See qf_parse_match() for details.
1141de3b3677SBram Moolenaar  */
1142de3b3677SBram Moolenaar static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) =
1143de3b3677SBram Moolenaar {
1144de3b3677SBram Moolenaar     NULL,
1145de3b3677SBram Moolenaar     qf_parse_fmt_n,
1146de3b3677SBram Moolenaar     qf_parse_fmt_l,
1147de3b3677SBram Moolenaar     qf_parse_fmt_c,
1148de3b3677SBram Moolenaar     qf_parse_fmt_t,
1149de3b3677SBram Moolenaar     qf_parse_fmt_m,
1150de3b3677SBram Moolenaar     NULL,
1151de3b3677SBram Moolenaar     qf_parse_fmt_p,
1152de3b3677SBram Moolenaar     qf_parse_fmt_v,
1153de3b3677SBram Moolenaar     qf_parse_fmt_s,
1154de3b3677SBram Moolenaar     qf_parse_fmt_o
1155de3b3677SBram Moolenaar };
1156de3b3677SBram Moolenaar 
1157de3b3677SBram Moolenaar /*
1158de3b3677SBram Moolenaar  * Parse the error format pattern matches in "regmatch" and set the values in
1159de3b3677SBram Moolenaar  * "fields".  fmt_ptr contains the 'efm' format specifiers/prefixes that have a
1160de3b3677SBram Moolenaar  * match.  Returns QF_OK if all the matches are successfully parsed. On
1161de3b3677SBram Moolenaar  * failure, returns QF_FAIL or QF_NOMEM.
1162e87e6dddSBram Moolenaar  */
1163e87e6dddSBram Moolenaar     static int
qf_parse_match(char_u * linebuf,int linelen,efm_T * fmt_ptr,regmatch_T * regmatch,qffields_T * fields,int qf_multiline,int qf_multiscan,char_u ** tail)116418cebf44SBram Moolenaar qf_parse_match(
1165e87e6dddSBram Moolenaar 	char_u		*linebuf,
1166e87e6dddSBram Moolenaar 	int		linelen,
116718cebf44SBram Moolenaar 	efm_T		*fmt_ptr,
116818cebf44SBram Moolenaar 	regmatch_T	*regmatch,
116918cebf44SBram Moolenaar 	qffields_T	*fields,
117018cebf44SBram Moolenaar 	int		qf_multiline,
117118cebf44SBram Moolenaar 	int		qf_multiscan,
117218cebf44SBram Moolenaar 	char_u		**tail)
1173e87e6dddSBram Moolenaar {
117418cebf44SBram Moolenaar     int		idx = fmt_ptr->prefix;
1175e87e6dddSBram Moolenaar     int		i;
1176de3b3677SBram Moolenaar     int		midx;
1177de3b3677SBram Moolenaar     int		status;
1178e87e6dddSBram Moolenaar 
117918cebf44SBram Moolenaar     if ((idx == 'C' || idx == 'Z') && !qf_multiline)
118018cebf44SBram Moolenaar 	return QF_FAIL;
1181e928366dSBram Moolenaar     if (vim_strchr((char_u *)"EWIN", idx) != NULL)
1182e87e6dddSBram Moolenaar 	fields->type = idx;
1183e87e6dddSBram Moolenaar     else
1184e87e6dddSBram Moolenaar 	fields->type = 0;
118500bf8cd2SBram Moolenaar 
118600bf8cd2SBram Moolenaar     // Extract error message data from matched line.
118700bf8cd2SBram Moolenaar     // We check for an actual submatch, because "\[" and "\]" in
118800bf8cd2SBram Moolenaar     // the 'errorformat' may cause the wrong submatch to be used.
1189de3b3677SBram Moolenaar     for (i = 0; i < FMT_PATTERNS; i++)
1190e87e6dddSBram Moolenaar     {
1191de3b3677SBram Moolenaar 	status = QF_OK;
1192de3b3677SBram Moolenaar 	midx = (int)fmt_ptr->addr[i];
119300bf8cd2SBram Moolenaar 	if (i == 0 && midx > 0)				// %f
1194de3b3677SBram Moolenaar 	    status = qf_parse_fmt_f(regmatch, midx, fields, idx);
1195de3b3677SBram Moolenaar 	else if (i == 5)
1196e87e6dddSBram Moolenaar 	{
119700bf8cd2SBram Moolenaar 	    if (fmt_ptr->flags == '+' && !qf_multiscan)	// %+
1198f4140488SBram Moolenaar 		status = copy_nonerror_line(linebuf, linelen, fields);
119900bf8cd2SBram Moolenaar 	    else if (midx > 0)				// %m
1200de3b3677SBram Moolenaar 		status = qf_parse_fmt_m(regmatch, midx, fields);
1201e87e6dddSBram Moolenaar 	}
120200bf8cd2SBram Moolenaar 	else if (i == 6 && midx > 0)			// %r
1203de3b3677SBram Moolenaar 	    status = qf_parse_fmt_r(regmatch, midx, tail);
120400bf8cd2SBram Moolenaar 	else if (midx > 0)				// others
1205de3b3677SBram Moolenaar 	    status = (qf_parse_fmt[i])(regmatch, midx, fields);
1206e87e6dddSBram Moolenaar 
1207de3b3677SBram Moolenaar 	if (status != QF_OK)
1208de3b3677SBram Moolenaar 	    return status;
1209d76ce852SBram Moolenaar     }
1210e87e6dddSBram Moolenaar 
121118cebf44SBram Moolenaar     return QF_OK;
121218cebf44SBram Moolenaar }
121318cebf44SBram Moolenaar 
121418cebf44SBram Moolenaar /*
121518cebf44SBram Moolenaar  * Parse an error line in 'linebuf' using a single error format string in
121618cebf44SBram Moolenaar  * 'fmt_ptr->prog' and return the matching values in 'fields'.
121718cebf44SBram Moolenaar  * Returns QF_OK if the efm format matches completely and the fields are
121818cebf44SBram Moolenaar  * successfully copied. Otherwise returns QF_FAIL or QF_NOMEM.
121918cebf44SBram Moolenaar  */
122018cebf44SBram Moolenaar     static int
qf_parse_get_fields(char_u * linebuf,int linelen,efm_T * fmt_ptr,qffields_T * fields,int qf_multiline,int qf_multiscan,char_u ** tail)122118cebf44SBram Moolenaar qf_parse_get_fields(
122218cebf44SBram Moolenaar 	char_u		*linebuf,
122318cebf44SBram Moolenaar 	int		linelen,
122418cebf44SBram Moolenaar 	efm_T		*fmt_ptr,
122518cebf44SBram Moolenaar 	qffields_T	*fields,
122618cebf44SBram Moolenaar 	int		qf_multiline,
122718cebf44SBram Moolenaar 	int		qf_multiscan,
122818cebf44SBram Moolenaar 	char_u		**tail)
1229e87e6dddSBram Moolenaar {
123018cebf44SBram Moolenaar     regmatch_T	regmatch;
123118cebf44SBram Moolenaar     int		status = QF_FAIL;
123218cebf44SBram Moolenaar     int		r;
123318cebf44SBram Moolenaar 
123418cebf44SBram Moolenaar     if (qf_multiscan &&
123518cebf44SBram Moolenaar 		vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL)
123618cebf44SBram Moolenaar 	return QF_FAIL;
123718cebf44SBram Moolenaar 
123818cebf44SBram Moolenaar     fields->namebuf[0] = NUL;
123918cebf44SBram Moolenaar     fields->module[0] = NUL;
124018cebf44SBram Moolenaar     fields->pattern[0] = NUL;
124118cebf44SBram Moolenaar     if (!qf_multiscan)
124218cebf44SBram Moolenaar 	fields->errmsg[0] = NUL;
124318cebf44SBram Moolenaar     fields->lnum = 0;
12446864efa5Sthinca     fields->end_lnum = 0;
124518cebf44SBram Moolenaar     fields->col = 0;
12466864efa5Sthinca     fields->end_col = 0;
124718cebf44SBram Moolenaar     fields->use_viscol = FALSE;
124818cebf44SBram Moolenaar     fields->enr = -1;
124918cebf44SBram Moolenaar     fields->type = 0;
125018cebf44SBram Moolenaar     *tail = NULL;
125118cebf44SBram Moolenaar 
125200bf8cd2SBram Moolenaar     // Always ignore case when looking for a matching error.
12538b62e310SBram Moolenaar     regmatch.rm_ic = TRUE;
125418cebf44SBram Moolenaar     regmatch.regprog = fmt_ptr->prog;
125518cebf44SBram Moolenaar     r = vim_regexec(&regmatch, linebuf, (colnr_T)0);
125618cebf44SBram Moolenaar     fmt_ptr->prog = regmatch.regprog;
125718cebf44SBram Moolenaar     if (r)
125818cebf44SBram Moolenaar 	status = qf_parse_match(linebuf, linelen, fmt_ptr, &regmatch,
125918cebf44SBram Moolenaar 		fields, qf_multiline, qf_multiscan, tail);
126018cebf44SBram Moolenaar 
126118cebf44SBram Moolenaar     return status;
126218cebf44SBram Moolenaar }
126318cebf44SBram Moolenaar 
126418cebf44SBram Moolenaar /*
126518cebf44SBram Moolenaar  * Parse directory error format prefixes (%D and %X).
126618cebf44SBram Moolenaar  * Push and pop directories from the directory stack when scanning directory
126718cebf44SBram Moolenaar  * names.
126818cebf44SBram Moolenaar  */
126918cebf44SBram Moolenaar     static int
qf_parse_dir_pfx(int idx,qffields_T * fields,qf_list_T * qfl)127018cebf44SBram Moolenaar qf_parse_dir_pfx(int idx, qffields_T *fields, qf_list_T *qfl)
1271e87e6dddSBram Moolenaar {
127200bf8cd2SBram Moolenaar     if (idx == 'D')				// enter directory
1273e87e6dddSBram Moolenaar     {
1274e87e6dddSBram Moolenaar 	if (*fields->namebuf == NUL)
1275e87e6dddSBram Moolenaar 	{
1276f9e3e09fSBram Moolenaar 	    emsg(_("E379: Missing or empty directory name"));
1277e87e6dddSBram Moolenaar 	    return QF_FAIL;
1278e87e6dddSBram Moolenaar 	}
1279a7df8c70SBram Moolenaar 	qfl->qf_directory =
1280a7df8c70SBram Moolenaar 	    qf_push_dir(fields->namebuf, &qfl->qf_dir_stack, FALSE);
1281a7df8c70SBram Moolenaar 	if (qfl->qf_directory == NULL)
1282e87e6dddSBram Moolenaar 	    return QF_FAIL;
1283e87e6dddSBram Moolenaar     }
128400bf8cd2SBram Moolenaar     else if (idx == 'X')			// leave directory
1285a7df8c70SBram Moolenaar 	qfl->qf_directory = qf_pop_dir(&qfl->qf_dir_stack);
128618cebf44SBram Moolenaar 
128718cebf44SBram Moolenaar     return QF_OK;
1288e87e6dddSBram Moolenaar }
128918cebf44SBram Moolenaar 
129018cebf44SBram Moolenaar /*
129118cebf44SBram Moolenaar  * Parse global file name error format prefixes (%O, %P and %Q).
129218cebf44SBram Moolenaar  */
129318cebf44SBram Moolenaar     static int
qf_parse_file_pfx(int idx,qffields_T * fields,qf_list_T * qfl,char_u * tail)129418cebf44SBram Moolenaar qf_parse_file_pfx(
129518cebf44SBram Moolenaar 	int idx,
129618cebf44SBram Moolenaar 	qffields_T *fields,
129718cebf44SBram Moolenaar 	qf_list_T *qfl,
129818cebf44SBram Moolenaar 	char_u *tail)
129918cebf44SBram Moolenaar {
130018cebf44SBram Moolenaar     fields->valid = FALSE;
130118cebf44SBram Moolenaar     if (*fields->namebuf == NUL || mch_getperm(fields->namebuf) >= 0)
130218cebf44SBram Moolenaar     {
130318cebf44SBram Moolenaar 	if (*fields->namebuf && idx == 'P')
130418cebf44SBram Moolenaar 	    qfl->qf_currfile =
130518cebf44SBram Moolenaar 		qf_push_dir(fields->namebuf, &qfl->qf_file_stack, TRUE);
130618cebf44SBram Moolenaar 	else if (idx == 'Q')
130718cebf44SBram Moolenaar 	    qfl->qf_currfile = qf_pop_dir(&qfl->qf_file_stack);
130818cebf44SBram Moolenaar 	*fields->namebuf = NUL;
130918cebf44SBram Moolenaar 	if (tail && *tail)
131018cebf44SBram Moolenaar 	{
131118cebf44SBram Moolenaar 	    STRMOVE(IObuff, skipwhite(tail));
131218cebf44SBram Moolenaar 	    qfl->qf_multiscan = TRUE;
131318cebf44SBram Moolenaar 	    return QF_MULTISCAN;
131418cebf44SBram Moolenaar 	}
131518cebf44SBram Moolenaar     }
131618cebf44SBram Moolenaar 
131718cebf44SBram Moolenaar     return QF_OK;
131818cebf44SBram Moolenaar }
131918cebf44SBram Moolenaar 
132018cebf44SBram Moolenaar /*
132118cebf44SBram Moolenaar  * Parse a non-error line (a line which doesn't match any of the error
132218cebf44SBram Moolenaar  * format in 'efm').
132318cebf44SBram Moolenaar  */
132418cebf44SBram Moolenaar     static int
qf_parse_line_nomatch(char_u * linebuf,int linelen,qffields_T * fields)132518cebf44SBram Moolenaar qf_parse_line_nomatch(char_u *linebuf, int linelen, qffields_T *fields)
132618cebf44SBram Moolenaar {
132700bf8cd2SBram Moolenaar     fields->namebuf[0] = NUL;	// no match found, remove file name
132800bf8cd2SBram Moolenaar     fields->lnum = 0;		// don't jump to this line
1329e87e6dddSBram Moolenaar     fields->valid = FALSE;
1330e87e6dddSBram Moolenaar 
1331f4140488SBram Moolenaar     return copy_nonerror_line(linebuf, linelen, fields);
1332e87e6dddSBram Moolenaar }
133318cebf44SBram Moolenaar 
133418cebf44SBram Moolenaar /*
133518cebf44SBram Moolenaar  * Parse multi-line error format prefixes (%C and %Z)
133618cebf44SBram Moolenaar  */
133718cebf44SBram Moolenaar     static int
qf_parse_multiline_pfx(int idx,qf_list_T * qfl,qffields_T * fields)133818cebf44SBram Moolenaar qf_parse_multiline_pfx(
133918cebf44SBram Moolenaar 	int idx,
134018cebf44SBram Moolenaar 	qf_list_T *qfl,
134118cebf44SBram Moolenaar 	qffields_T *fields)
134218cebf44SBram Moolenaar {
134318cebf44SBram Moolenaar     char_u		*ptr;
134418cebf44SBram Moolenaar     int			len;
134518cebf44SBram Moolenaar 
1346a7df8c70SBram Moolenaar     if (!qfl->qf_multiignore)
13479b457948SBram Moolenaar     {
1348a7df8c70SBram Moolenaar 	qfline_T *qfprev = qfl->qf_last;
1349e87e6dddSBram Moolenaar 
1350e87e6dddSBram Moolenaar 	if (qfprev == NULL)
1351e87e6dddSBram Moolenaar 	    return QF_FAIL;
1352a7df8c70SBram Moolenaar 	if (*fields->errmsg && !qfl->qf_multiignore)
1353e87e6dddSBram Moolenaar 	{
1354e87e6dddSBram Moolenaar 	    len = (int)STRLEN(qfprev->qf_text);
1355964b3746SBram Moolenaar 	    if ((ptr = alloc(len + STRLEN(fields->errmsg) + 2))
1356e87e6dddSBram Moolenaar 		    == NULL)
1357e87e6dddSBram Moolenaar 		return QF_FAIL;
1358e87e6dddSBram Moolenaar 	    STRCPY(ptr, qfprev->qf_text);
1359e87e6dddSBram Moolenaar 	    vim_free(qfprev->qf_text);
1360e87e6dddSBram Moolenaar 	    qfprev->qf_text = ptr;
1361e87e6dddSBram Moolenaar 	    *(ptr += len) = '\n';
1362e87e6dddSBram Moolenaar 	    STRCPY(++ptr, fields->errmsg);
1363e87e6dddSBram Moolenaar 	}
1364e87e6dddSBram Moolenaar 	if (qfprev->qf_nr == -1)
1365e87e6dddSBram Moolenaar 	    qfprev->qf_nr = fields->enr;
1366e87e6dddSBram Moolenaar 	if (vim_isprintc(fields->type) && !qfprev->qf_type)
136700bf8cd2SBram Moolenaar 	    // only printable chars allowed
1368e87e6dddSBram Moolenaar 	    qfprev->qf_type = fields->type;
1369e87e6dddSBram Moolenaar 
1370e87e6dddSBram Moolenaar 	if (!qfprev->qf_lnum)
1371e87e6dddSBram Moolenaar 	    qfprev->qf_lnum = fields->lnum;
1372e87e6dddSBram Moolenaar 	if (!qfprev->qf_col)
1373c95940c0SBram Moolenaar 	{
1374e87e6dddSBram Moolenaar 	    qfprev->qf_col = fields->col;
1375e87e6dddSBram Moolenaar 	    qfprev->qf_viscol = fields->use_viscol;
1376c95940c0SBram Moolenaar 	}
1377e87e6dddSBram Moolenaar 	if (!qfprev->qf_fnum)
13780398e00aSBram Moolenaar 	    qfprev->qf_fnum = qf_get_fnum(qfl,
1379a7df8c70SBram Moolenaar 		    qfl->qf_directory,
1380a7df8c70SBram Moolenaar 		    *fields->namebuf || qfl->qf_directory != NULL
1381e87e6dddSBram Moolenaar 		    ? fields->namebuf
1382a7df8c70SBram Moolenaar 		    : qfl->qf_currfile != NULL && fields->valid
1383a7df8c70SBram Moolenaar 		    ? qfl->qf_currfile : 0);
13849b457948SBram Moolenaar     }
1385e87e6dddSBram Moolenaar     if (idx == 'Z')
1386a7df8c70SBram Moolenaar 	qfl->qf_multiline = qfl->qf_multiignore = FALSE;
1387e87e6dddSBram Moolenaar     line_breakcheck();
138818cebf44SBram Moolenaar 
1389e87e6dddSBram Moolenaar     return QF_IGNORE_LINE;
1390e87e6dddSBram Moolenaar }
139118cebf44SBram Moolenaar 
139218cebf44SBram Moolenaar /*
139318cebf44SBram Moolenaar  * Parse a line and get the quickfix fields.
139418cebf44SBram Moolenaar  * Return the QF_ status.
139518cebf44SBram Moolenaar  */
139618cebf44SBram Moolenaar     static int
qf_parse_line(qf_list_T * qfl,char_u * linebuf,int linelen,efm_T * fmt_first,qffields_T * fields)139718cebf44SBram Moolenaar qf_parse_line(
13980398e00aSBram Moolenaar 	qf_list_T	*qfl,
139918cebf44SBram Moolenaar 	char_u		*linebuf,
140018cebf44SBram Moolenaar 	int		linelen,
140118cebf44SBram Moolenaar 	efm_T		*fmt_first,
140218cebf44SBram Moolenaar 	qffields_T	*fields)
140318cebf44SBram Moolenaar {
140418cebf44SBram Moolenaar     efm_T		*fmt_ptr;
140518cebf44SBram Moolenaar     int			idx = 0;
140618cebf44SBram Moolenaar     char_u		*tail = NULL;
140718cebf44SBram Moolenaar     int			status;
140818cebf44SBram Moolenaar 
140918cebf44SBram Moolenaar restofline:
141000bf8cd2SBram Moolenaar     // If there was no %> item start at the first pattern
141118cebf44SBram Moolenaar     if (fmt_start == NULL)
141218cebf44SBram Moolenaar 	fmt_ptr = fmt_first;
141318cebf44SBram Moolenaar     else
141418cebf44SBram Moolenaar     {
141500bf8cd2SBram Moolenaar 	// Otherwise start from the last used pattern
141618cebf44SBram Moolenaar 	fmt_ptr = fmt_start;
141718cebf44SBram Moolenaar 	fmt_start = NULL;
141818cebf44SBram Moolenaar     }
141918cebf44SBram Moolenaar 
142000bf8cd2SBram Moolenaar     // Try to match each part of 'errorformat' until we find a complete
142100bf8cd2SBram Moolenaar     // match or no match.
142218cebf44SBram Moolenaar     fields->valid = TRUE;
142318cebf44SBram Moolenaar     for ( ; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next)
142418cebf44SBram Moolenaar     {
142518cebf44SBram Moolenaar 	idx = fmt_ptr->prefix;
142618cebf44SBram Moolenaar 	status = qf_parse_get_fields(linebuf, linelen, fmt_ptr, fields,
142718cebf44SBram Moolenaar 				qfl->qf_multiline, qfl->qf_multiscan, &tail);
142818cebf44SBram Moolenaar 	if (status == QF_NOMEM)
142918cebf44SBram Moolenaar 	    return status;
143018cebf44SBram Moolenaar 	if (status == QF_OK)
143118cebf44SBram Moolenaar 	    break;
143218cebf44SBram Moolenaar     }
143318cebf44SBram Moolenaar     qfl->qf_multiscan = FALSE;
143418cebf44SBram Moolenaar 
143518cebf44SBram Moolenaar     if (fmt_ptr == NULL || idx == 'D' || idx == 'X')
143618cebf44SBram Moolenaar     {
143718cebf44SBram Moolenaar 	if (fmt_ptr != NULL)
143818cebf44SBram Moolenaar 	{
143900bf8cd2SBram Moolenaar 	    // 'D' and 'X' directory specifiers
144018cebf44SBram Moolenaar 	    status = qf_parse_dir_pfx(idx, fields, qfl);
144118cebf44SBram Moolenaar 	    if (status != QF_OK)
144218cebf44SBram Moolenaar 		return status;
144318cebf44SBram Moolenaar 	}
144418cebf44SBram Moolenaar 
144518cebf44SBram Moolenaar 	status = qf_parse_line_nomatch(linebuf, linelen, fields);
144618cebf44SBram Moolenaar 	if (status != QF_OK)
144718cebf44SBram Moolenaar 	    return status;
144818cebf44SBram Moolenaar 
144918cebf44SBram Moolenaar 	if (fmt_ptr == NULL)
145018cebf44SBram Moolenaar 	    qfl->qf_multiline = qfl->qf_multiignore = FALSE;
145118cebf44SBram Moolenaar     }
145218cebf44SBram Moolenaar     else if (fmt_ptr != NULL)
145318cebf44SBram Moolenaar     {
145400bf8cd2SBram Moolenaar 	// honor %> item
145518cebf44SBram Moolenaar 	if (fmt_ptr->conthere)
145618cebf44SBram Moolenaar 	    fmt_start = fmt_ptr;
145718cebf44SBram Moolenaar 
1458e928366dSBram Moolenaar 	if (vim_strchr((char_u *)"AEWIN", idx) != NULL)
145918cebf44SBram Moolenaar 	{
146000bf8cd2SBram Moolenaar 	    qfl->qf_multiline = TRUE;	// start of a multi-line message
146100bf8cd2SBram Moolenaar 	    qfl->qf_multiignore = FALSE;// reset continuation
146218cebf44SBram Moolenaar 	}
146318cebf44SBram Moolenaar 	else if (vim_strchr((char_u *)"CZ", idx) != NULL)
146400bf8cd2SBram Moolenaar 	{				// continuation of multi-line msg
14650398e00aSBram Moolenaar 	    status = qf_parse_multiline_pfx(idx, qfl, fields);
146618cebf44SBram Moolenaar 	    if (status != QF_OK)
146718cebf44SBram Moolenaar 		return status;
146818cebf44SBram Moolenaar 	}
1469e87e6dddSBram Moolenaar 	else if (vim_strchr((char_u *)"OPQ", idx) != NULL)
147000bf8cd2SBram Moolenaar 	{				// global file names
147118cebf44SBram Moolenaar 	    status = qf_parse_file_pfx(idx, fields, qfl, tail);
147218cebf44SBram Moolenaar 	    if (status == QF_MULTISCAN)
1473e87e6dddSBram Moolenaar 		goto restofline;
1474e87e6dddSBram Moolenaar 	}
147500bf8cd2SBram Moolenaar 	if (fmt_ptr->flags == '-')	// generally exclude this line
1476e87e6dddSBram Moolenaar 	{
1477a7df8c70SBram Moolenaar 	    if (qfl->qf_multiline)
147800bf8cd2SBram Moolenaar 		// also exclude continuation lines
1479a7df8c70SBram Moolenaar 		qfl->qf_multiignore = TRUE;
1480e87e6dddSBram Moolenaar 	    return QF_IGNORE_LINE;
1481e87e6dddSBram Moolenaar 	}
1482e87e6dddSBram Moolenaar     }
1483e87e6dddSBram Moolenaar 
1484e87e6dddSBram Moolenaar     return QF_OK;
1485e87e6dddSBram Moolenaar }
1486e87e6dddSBram Moolenaar 
1487071d4279SBram Moolenaar /*
1488019dfe68SBram Moolenaar  * Returns TRUE if the specified quickfix/location stack is empty
1489019dfe68SBram Moolenaar  */
1490019dfe68SBram Moolenaar     static int
qf_stack_empty(qf_info_T * qi)1491019dfe68SBram Moolenaar qf_stack_empty(qf_info_T *qi)
1492019dfe68SBram Moolenaar {
1493019dfe68SBram Moolenaar     return qi == NULL || qi->qf_listcount <= 0;
1494019dfe68SBram Moolenaar }
1495019dfe68SBram Moolenaar 
1496019dfe68SBram Moolenaar /*
1497de3b3677SBram Moolenaar  * Returns TRUE if the specified quickfix/location list is empty.
1498de3b3677SBram Moolenaar  */
1499de3b3677SBram Moolenaar     static int
qf_list_empty(qf_list_T * qfl)15000398e00aSBram Moolenaar qf_list_empty(qf_list_T *qfl)
1501de3b3677SBram Moolenaar {
15020398e00aSBram Moolenaar     return qfl == NULL || qfl->qf_count <= 0;
15030398e00aSBram Moolenaar }
15040398e00aSBram Moolenaar 
15050398e00aSBram Moolenaar /*
15063ff33114SBram Moolenaar  * Returns TRUE if the specified quickfix/location list is not empty and
15073ff33114SBram Moolenaar  * has valid entries.
15083ff33114SBram Moolenaar  */
15093ff33114SBram Moolenaar     static int
qf_list_has_valid_entries(qf_list_T * qfl)15103ff33114SBram Moolenaar qf_list_has_valid_entries(qf_list_T *qfl)
15113ff33114SBram Moolenaar {
15123ff33114SBram Moolenaar     return !qf_list_empty(qfl) && !qfl->qf_nonevalid;
15133ff33114SBram Moolenaar }
15143ff33114SBram Moolenaar 
15153ff33114SBram Moolenaar /*
15160398e00aSBram Moolenaar  * Return a pointer to a list in the specified quickfix stack
15170398e00aSBram Moolenaar  */
15180398e00aSBram Moolenaar     static qf_list_T *
qf_get_list(qf_info_T * qi,int idx)15190398e00aSBram Moolenaar qf_get_list(qf_info_T *qi, int idx)
15200398e00aSBram Moolenaar {
15210398e00aSBram Moolenaar     return &qi->qf_lists[idx];
1522de3b3677SBram Moolenaar }
1523de3b3677SBram Moolenaar 
1524de3b3677SBram Moolenaar /*
15256053f2d2SBram Moolenaar  * Allocate the fields used for parsing lines and populating a quickfix list.
15266053f2d2SBram Moolenaar  */
15276053f2d2SBram Moolenaar     static int
qf_alloc_fields(qffields_T * pfields)15286053f2d2SBram Moolenaar qf_alloc_fields(qffields_T *pfields)
15296053f2d2SBram Moolenaar {
15306053f2d2SBram Moolenaar     pfields->namebuf = alloc_id(CMDBUFFSIZE + 1, aid_qf_namebuf);
15316053f2d2SBram Moolenaar     pfields->module = alloc_id(CMDBUFFSIZE + 1, aid_qf_module);
15326053f2d2SBram Moolenaar     pfields->errmsglen = CMDBUFFSIZE + 1;
15336053f2d2SBram Moolenaar     pfields->errmsg = alloc_id(pfields->errmsglen, aid_qf_errmsg);
15346053f2d2SBram Moolenaar     pfields->pattern = alloc_id(CMDBUFFSIZE + 1, aid_qf_pattern);
15356053f2d2SBram Moolenaar     if (pfields->namebuf == NULL || pfields->errmsg == NULL
15366053f2d2SBram Moolenaar 		|| pfields->pattern == NULL || pfields->module == NULL)
15376053f2d2SBram Moolenaar 	return FAIL;
15386053f2d2SBram Moolenaar 
15396053f2d2SBram Moolenaar     return OK;
15406053f2d2SBram Moolenaar }
15416053f2d2SBram Moolenaar 
15426053f2d2SBram Moolenaar /*
15436053f2d2SBram Moolenaar  * Free the fields used for parsing lines and populating a quickfix list.
15446053f2d2SBram Moolenaar  */
15456053f2d2SBram Moolenaar     static void
qf_free_fields(qffields_T * pfields)15466053f2d2SBram Moolenaar qf_free_fields(qffields_T *pfields)
15476053f2d2SBram Moolenaar {
15486053f2d2SBram Moolenaar     vim_free(pfields->namebuf);
15496053f2d2SBram Moolenaar     vim_free(pfields->module);
15506053f2d2SBram Moolenaar     vim_free(pfields->errmsg);
15516053f2d2SBram Moolenaar     vim_free(pfields->pattern);
15526053f2d2SBram Moolenaar }
15536053f2d2SBram Moolenaar 
15546053f2d2SBram Moolenaar /*
15556053f2d2SBram Moolenaar  * Setup the state information used for parsing lines and populating a
15566053f2d2SBram Moolenaar  * quickfix list.
15576053f2d2SBram Moolenaar  */
15586053f2d2SBram Moolenaar     static int
qf_setup_state(qfstate_T * pstate,char_u * enc,char_u * efile,typval_T * tv,buf_T * buf,linenr_T lnumfirst,linenr_T lnumlast)15596053f2d2SBram Moolenaar qf_setup_state(
15606053f2d2SBram Moolenaar 	qfstate_T	*pstate,
15616053f2d2SBram Moolenaar 	char_u		*enc,
15626053f2d2SBram Moolenaar 	char_u		*efile,
15636053f2d2SBram Moolenaar 	typval_T	*tv,
15646053f2d2SBram Moolenaar 	buf_T		*buf,
15656053f2d2SBram Moolenaar 	linenr_T	lnumfirst,
15666053f2d2SBram Moolenaar 	linenr_T	lnumlast)
15676053f2d2SBram Moolenaar {
15686053f2d2SBram Moolenaar     pstate->vc.vc_type = CONV_NONE;
15696053f2d2SBram Moolenaar     if (enc != NULL && *enc != NUL)
15706053f2d2SBram Moolenaar 	convert_setup(&pstate->vc, enc, p_enc);
15716053f2d2SBram Moolenaar 
15726053f2d2SBram Moolenaar     if (efile != NULL && (pstate->fd = mch_fopen((char *)efile, "r")) == NULL)
15736053f2d2SBram Moolenaar     {
1574e29a27f6SBram Moolenaar 	semsg(_(e_cant_open_errorfile_str), efile);
15756053f2d2SBram Moolenaar 	return FAIL;
15766053f2d2SBram Moolenaar     }
15776053f2d2SBram Moolenaar 
15786053f2d2SBram Moolenaar     if (tv != NULL)
15796053f2d2SBram Moolenaar     {
15806053f2d2SBram Moolenaar 	if (tv->v_type == VAR_STRING)
15816053f2d2SBram Moolenaar 	    pstate->p_str = tv->vval.v_string;
15826053f2d2SBram Moolenaar 	else if (tv->v_type == VAR_LIST)
15836053f2d2SBram Moolenaar 	    pstate->p_li = tv->vval.v_list->lv_first;
15846053f2d2SBram Moolenaar 	pstate->tv = tv;
15856053f2d2SBram Moolenaar     }
15866053f2d2SBram Moolenaar     pstate->buf = buf;
15876053f2d2SBram Moolenaar     pstate->buflnum = lnumfirst;
15886053f2d2SBram Moolenaar     pstate->lnumlast = lnumlast;
15896053f2d2SBram Moolenaar 
15906053f2d2SBram Moolenaar     return OK;
15916053f2d2SBram Moolenaar }
15926053f2d2SBram Moolenaar 
15936053f2d2SBram Moolenaar /*
15946053f2d2SBram Moolenaar  * Cleanup the state information used for parsing lines and populating a
15956053f2d2SBram Moolenaar  * quickfix list.
15966053f2d2SBram Moolenaar  */
15976053f2d2SBram Moolenaar     static void
qf_cleanup_state(qfstate_T * pstate)15986053f2d2SBram Moolenaar qf_cleanup_state(qfstate_T *pstate)
15996053f2d2SBram Moolenaar {
16006053f2d2SBram Moolenaar     if (pstate->fd != NULL)
16016053f2d2SBram Moolenaar 	fclose(pstate->fd);
16026053f2d2SBram Moolenaar 
16036053f2d2SBram Moolenaar     vim_free(pstate->growbuf);
16046053f2d2SBram Moolenaar     if (pstate->vc.vc_type != CONV_NONE)
16056053f2d2SBram Moolenaar 	convert_setup(&pstate->vc, NULL, NULL);
16066053f2d2SBram Moolenaar }
16076053f2d2SBram Moolenaar 
16086053f2d2SBram Moolenaar /*
160995946f12SBram Moolenaar  * Process the next line from a file/buffer/list/string and add it
161095946f12SBram Moolenaar  * to the quickfix list 'qfl'.
161195946f12SBram Moolenaar  */
161295946f12SBram Moolenaar     static int
qf_init_process_nextline(qf_list_T * qfl,efm_T * fmt_first,qfstate_T * state,qffields_T * fields)161395946f12SBram Moolenaar qf_init_process_nextline(
161495946f12SBram Moolenaar 	qf_list_T	*qfl,
161595946f12SBram Moolenaar 	efm_T		*fmt_first,
161695946f12SBram Moolenaar 	qfstate_T	*state,
161795946f12SBram Moolenaar 	qffields_T	*fields)
161895946f12SBram Moolenaar {
161995946f12SBram Moolenaar     int		    status;
162095946f12SBram Moolenaar 
162195946f12SBram Moolenaar     // Get the next line from a file/buffer/list/string
162295946f12SBram Moolenaar     status = qf_get_nextline(state);
162395946f12SBram Moolenaar     if (status != QF_OK)
162495946f12SBram Moolenaar 	return status;
162595946f12SBram Moolenaar 
162695946f12SBram Moolenaar     status = qf_parse_line(qfl, state->linebuf, state->linelen,
162795946f12SBram Moolenaar 	    fmt_first, fields);
162895946f12SBram Moolenaar     if (status != QF_OK)
162995946f12SBram Moolenaar 	return status;
163095946f12SBram Moolenaar 
163195946f12SBram Moolenaar     return qf_add_entry(qfl,
163295946f12SBram Moolenaar 		qfl->qf_directory,
163395946f12SBram Moolenaar 		(*fields->namebuf || qfl->qf_directory != NULL)
163495946f12SBram Moolenaar 		? fields->namebuf
163595946f12SBram Moolenaar 		: ((qfl->qf_currfile != NULL && fields->valid)
163695946f12SBram Moolenaar 		    ? qfl->qf_currfile : (char_u *)NULL),
163795946f12SBram Moolenaar 		fields->module,
163895946f12SBram Moolenaar 		0,
163995946f12SBram Moolenaar 		fields->errmsg,
164095946f12SBram Moolenaar 		fields->lnum,
16416864efa5Sthinca 		fields->end_lnum,
164295946f12SBram Moolenaar 		fields->col,
16436864efa5Sthinca 		fields->end_col,
164495946f12SBram Moolenaar 		fields->use_viscol,
164595946f12SBram Moolenaar 		fields->pattern,
164695946f12SBram Moolenaar 		fields->enr,
164795946f12SBram Moolenaar 		fields->type,
164895946f12SBram Moolenaar 		fields->valid);
164995946f12SBram Moolenaar }
165095946f12SBram Moolenaar 
165195946f12SBram Moolenaar /*
1652688e3d1fSBram Moolenaar  * Read the errorfile "efile" into memory, line by line, building the error
1653688e3d1fSBram Moolenaar  * list.
1654688e3d1fSBram Moolenaar  * Alternative: when "efile" is NULL read errors from buffer "buf".
1655688e3d1fSBram Moolenaar  * Alternative: when "tv" is not NULL get errors from the string or list.
1656688e3d1fSBram Moolenaar  * Always use 'errorformat' from "buf" if there is a local value.
1657688e3d1fSBram Moolenaar  * Then "lnumfirst" and "lnumlast" specify the range of lines to use.
1658688e3d1fSBram Moolenaar  * Set the title of the list to "qf_title".
1659688e3d1fSBram Moolenaar  * Return -1 for error, number of errors for success.
1660688e3d1fSBram Moolenaar  */
1661688e3d1fSBram Moolenaar     static int
qf_init_ext(qf_info_T * qi,int qf_idx,char_u * efile,buf_T * buf,typval_T * tv,char_u * errorformat,int newlist,linenr_T lnumfirst,linenr_T lnumlast,char_u * qf_title,char_u * enc)1662688e3d1fSBram Moolenaar qf_init_ext(
1663688e3d1fSBram Moolenaar     qf_info_T	    *qi,
1664a7df8c70SBram Moolenaar     int		    qf_idx,
1665688e3d1fSBram Moolenaar     char_u	    *efile,
1666688e3d1fSBram Moolenaar     buf_T	    *buf,
1667688e3d1fSBram Moolenaar     typval_T	    *tv,
1668688e3d1fSBram Moolenaar     char_u	    *errorformat,
166900bf8cd2SBram Moolenaar     int		    newlist,		// TRUE: start a new error list
167000bf8cd2SBram Moolenaar     linenr_T	    lnumfirst,		// first line number to use
167100bf8cd2SBram Moolenaar     linenr_T	    lnumlast,		// last line number to use
16722c7292dcSBram Moolenaar     char_u	    *qf_title,
16732c7292dcSBram Moolenaar     char_u	    *enc)
1674688e3d1fSBram Moolenaar {
1675a7df8c70SBram Moolenaar     qf_list_T	    *qfl;
16762c7292dcSBram Moolenaar     qfstate_T	    state;
16772c7292dcSBram Moolenaar     qffields_T	    fields;
1678688e3d1fSBram Moolenaar     qfline_T	    *old_last = NULL;
167986f100dcSBram Moolenaar     int		    adding = FALSE;
1680361c8f0eSBram Moolenaar     static efm_T    *fmt_first = NULL;
1681688e3d1fSBram Moolenaar     char_u	    *efm;
1682361c8f0eSBram Moolenaar     static char_u   *last_efm = NULL;
168300bf8cd2SBram Moolenaar     int		    retval = -1;	// default: return error flag
1684e0d37976SBram Moolenaar     int		    status;
1685688e3d1fSBram Moolenaar 
168600bf8cd2SBram Moolenaar     // Do not used the cached buffer, it may have been wiped out.
1687d23a8236SBram Moolenaar     VIM_CLEAR(qf_last_bufname);
16886dd4a535SBram Moolenaar 
1689a80faa89SBram Moolenaar     CLEAR_FIELD(state);
1690a80faa89SBram Moolenaar     CLEAR_FIELD(fields);
16916053f2d2SBram Moolenaar     if ((qf_alloc_fields(&fields) == FAIL) ||
16926053f2d2SBram Moolenaar 		(qf_setup_state(&state, enc, efile, tv, buf,
16936053f2d2SBram Moolenaar 					lnumfirst, lnumlast) == FAIL))
1694688e3d1fSBram Moolenaar 	goto qf_init_end;
1695688e3d1fSBram Moolenaar 
1696a7df8c70SBram Moolenaar     if (newlist || qf_idx == qi->qf_listcount)
1697a7df8c70SBram Moolenaar     {
169800bf8cd2SBram Moolenaar 	// make place for a new list
1699688e3d1fSBram Moolenaar 	qf_new_list(qi, qf_title);
1700a7df8c70SBram Moolenaar 	qf_idx = qi->qf_curlist;
17019afe5e9cSBram Moolenaar 	qfl = qf_get_list(qi, qf_idx);
1702a7df8c70SBram Moolenaar     }
170386f100dcSBram Moolenaar     else
1704688e3d1fSBram Moolenaar     {
170500bf8cd2SBram Moolenaar 	// Adding to existing list, use last entry.
17062b946c9fSBram Moolenaar 	adding = TRUE;
17070398e00aSBram Moolenaar 	qfl = qf_get_list(qi, qf_idx);
17089afe5e9cSBram Moolenaar 	if (!qf_list_empty(qfl))
17099afe5e9cSBram Moolenaar 	    old_last = qfl->qf_last;
17109afe5e9cSBram Moolenaar     }
1711a7df8c70SBram Moolenaar 
171200bf8cd2SBram Moolenaar     // Use the local value of 'errorformat' if it's set.
1713688e3d1fSBram Moolenaar     if (errorformat == p_efm && tv == NULL && *buf->b_p_efm != NUL)
1714688e3d1fSBram Moolenaar 	efm = buf->b_p_efm;
1715688e3d1fSBram Moolenaar     else
1716688e3d1fSBram Moolenaar 	efm = errorformat;
1717688e3d1fSBram Moolenaar 
171800bf8cd2SBram Moolenaar     // If the errorformat didn't change between calls, then reuse the
171900bf8cd2SBram Moolenaar     // previously parsed values.
1720361c8f0eSBram Moolenaar     if (last_efm == NULL || (STRCMP(last_efm, efm) != 0))
1721361c8f0eSBram Moolenaar     {
172200bf8cd2SBram Moolenaar 	// free the previously parsed data
1723d23a8236SBram Moolenaar 	VIM_CLEAR(last_efm);
1724361c8f0eSBram Moolenaar 	free_efm_list(&fmt_first);
1725361c8f0eSBram Moolenaar 
172600bf8cd2SBram Moolenaar 	// parse the current 'efm'
1727688e3d1fSBram Moolenaar 	fmt_first = parse_efm_option(efm);
1728361c8f0eSBram Moolenaar 	if (fmt_first != NULL)
1729361c8f0eSBram Moolenaar 	    last_efm = vim_strsave(efm);
1730361c8f0eSBram Moolenaar     }
1731361c8f0eSBram Moolenaar 
173200bf8cd2SBram Moolenaar     if (fmt_first == NULL)	// nothing found
1733688e3d1fSBram Moolenaar 	goto error2;
1734688e3d1fSBram Moolenaar 
173500bf8cd2SBram Moolenaar     // got_int is reset here, because it was probably set when killing the
173600bf8cd2SBram Moolenaar     // ":make" command, but we still want to read the errorfile then.
1737071d4279SBram Moolenaar     got_int = FALSE;
1738071d4279SBram Moolenaar 
173900bf8cd2SBram Moolenaar     // Read the lines in the error file one by one.
174000bf8cd2SBram Moolenaar     // Try to recognize one of the error formats in each line.
174186b68359SBram Moolenaar     while (!got_int)
1742071d4279SBram Moolenaar     {
174395946f12SBram Moolenaar 	status = qf_init_process_nextline(qfl, fmt_first, &state, &fields);
174400bf8cd2SBram Moolenaar 	if (status == QF_NOMEM)		// memory alloc failure
17456be8c8e1SBram Moolenaar 	    goto qf_init_end;
174600bf8cd2SBram Moolenaar 	if (status == QF_END_OF_INPUT)	// end of input
174787e25fdfSBram Moolenaar 	    break;
1748e87e6dddSBram Moolenaar 	if (status == QF_FAIL)
1749e87e6dddSBram Moolenaar 	    goto error2;
1750071d4279SBram Moolenaar 
1751071d4279SBram Moolenaar 	line_breakcheck();
1752071d4279SBram Moolenaar     }
1753e0d37976SBram Moolenaar     if (state.fd == NULL || !ferror(state.fd))
1754071d4279SBram Moolenaar     {
1755a7df8c70SBram Moolenaar 	if (qfl->qf_index == 0)
1756071d4279SBram Moolenaar 	{
175700bf8cd2SBram Moolenaar 	    // no valid entry found
1758a7df8c70SBram Moolenaar 	    qfl->qf_ptr = qfl->qf_start;
1759a7df8c70SBram Moolenaar 	    qfl->qf_index = 1;
1760a7df8c70SBram Moolenaar 	    qfl->qf_nonevalid = TRUE;
1761071d4279SBram Moolenaar 	}
1762071d4279SBram Moolenaar 	else
1763071d4279SBram Moolenaar 	{
1764a7df8c70SBram Moolenaar 	    qfl->qf_nonevalid = FALSE;
1765a7df8c70SBram Moolenaar 	    if (qfl->qf_ptr == NULL)
1766a7df8c70SBram Moolenaar 		qfl->qf_ptr = qfl->qf_start;
1767071d4279SBram Moolenaar 	}
176800bf8cd2SBram Moolenaar 	// return number of matches
1769a7df8c70SBram Moolenaar 	retval = qfl->qf_count;
1770bcf7772aSBram Moolenaar 	goto qf_init_end;
1771071d4279SBram Moolenaar     }
1772d8e44476SBram Moolenaar     emsg(_(e_error_while_reading_errorfile));
1773071d4279SBram Moolenaar error2:
17742b946c9fSBram Moolenaar     if (!adding)
17752b946c9fSBram Moolenaar     {
177600bf8cd2SBram Moolenaar 	// Error when creating a new list. Free the new list
1777108e7b42SBram Moolenaar 	qf_free(qfl);
1778d12f5c17SBram Moolenaar 	qi->qf_listcount--;
1779d12f5c17SBram Moolenaar 	if (qi->qf_curlist > 0)
1780d12f5c17SBram Moolenaar 	    --qi->qf_curlist;
17812b946c9fSBram Moolenaar     }
1782bcf7772aSBram Moolenaar qf_init_end:
1783a7df8c70SBram Moolenaar     if (qf_idx == qi->qf_curlist)
1784864293abSBram Moolenaar 	qf_update_buffer(qi, old_last);
17856053f2d2SBram Moolenaar     qf_cleanup_state(&state);
17866053f2d2SBram Moolenaar     qf_free_fields(&fields);
1787071d4279SBram Moolenaar 
1788071d4279SBram Moolenaar     return retval;
1789071d4279SBram Moolenaar }
1790071d4279SBram Moolenaar 
179118cebf44SBram Moolenaar /*
17926053f2d2SBram Moolenaar  * Read the errorfile "efile" into memory, line by line, building the error
17936053f2d2SBram Moolenaar  * list. Set the error list's title to qf_title.
17946053f2d2SBram Moolenaar  * Return -1 for error, number of errors for success.
17956053f2d2SBram Moolenaar  */
17966053f2d2SBram Moolenaar     int
qf_init(win_T * wp,char_u * efile,char_u * errorformat,int newlist,char_u * qf_title,char_u * enc)17976053f2d2SBram Moolenaar qf_init(win_T	    *wp,
17986053f2d2SBram Moolenaar 	char_u	    *efile,
17996053f2d2SBram Moolenaar 	char_u	    *errorformat,
180000bf8cd2SBram Moolenaar 	int	    newlist,		// TRUE: start a new error list
18016053f2d2SBram Moolenaar 	char_u	    *qf_title,
18026053f2d2SBram Moolenaar 	char_u	    *enc)
18036053f2d2SBram Moolenaar {
18046053f2d2SBram Moolenaar     qf_info_T	    *qi = &ql_info;
18056053f2d2SBram Moolenaar 
18066053f2d2SBram Moolenaar     if (wp != NULL)
18076053f2d2SBram Moolenaar     {
18086053f2d2SBram Moolenaar 	qi = ll_get_or_alloc_list(wp);
18096053f2d2SBram Moolenaar 	if (qi == NULL)
18106053f2d2SBram Moolenaar 	    return FAIL;
18116053f2d2SBram Moolenaar     }
18126053f2d2SBram Moolenaar 
18136053f2d2SBram Moolenaar     return qf_init_ext(qi, qi->qf_curlist, efile, curbuf, NULL, errorformat,
18146053f2d2SBram Moolenaar 	    newlist, (linenr_T)0, (linenr_T)0, qf_title, enc);
18156053f2d2SBram Moolenaar }
18166053f2d2SBram Moolenaar 
18176053f2d2SBram Moolenaar /*
181818cebf44SBram Moolenaar  * Set the title of the specified quickfix list. Frees the previous title.
181918cebf44SBram Moolenaar  * Prepends ':' to the title.
182018cebf44SBram Moolenaar  */
1821fb60409aSBram Moolenaar     static void
qf_store_title(qf_list_T * qfl,char_u * title)1822fe15b7dfSBram Moolenaar qf_store_title(qf_list_T *qfl, char_u *title)
1823fb60409aSBram Moolenaar {
1824fe15b7dfSBram Moolenaar     VIM_CLEAR(qfl->qf_title);
18256a8958dbSBram Moolenaar 
1826fb60409aSBram Moolenaar     if (title != NULL)
1827fb60409aSBram Moolenaar     {
182851e14387SBram Moolenaar 	char_u *p = alloc(STRLEN(title) + 2);
1829fb60409aSBram Moolenaar 
1830fe15b7dfSBram Moolenaar 	qfl->qf_title = p;
1831fb60409aSBram Moolenaar 	if (p != NULL)
18328b62e310SBram Moolenaar 	    STRCPY(p, title);
1833fb60409aSBram Moolenaar     }
1834fb60409aSBram Moolenaar }
1835fb60409aSBram Moolenaar 
1836071d4279SBram Moolenaar /*
18378b62e310SBram Moolenaar  * The title of a quickfix/location list is set, by default, to the command
18388b62e310SBram Moolenaar  * that created the quickfix list with the ":" prefix.
18398b62e310SBram Moolenaar  * Create a quickfix list title string by prepending ":" to a user command.
18408b62e310SBram Moolenaar  * Returns a pointer to a static buffer with the title.
18418b62e310SBram Moolenaar  */
18428b62e310SBram Moolenaar     static char_u *
qf_cmdtitle(char_u * cmd)18438b62e310SBram Moolenaar qf_cmdtitle(char_u *cmd)
18448b62e310SBram Moolenaar {
18458b62e310SBram Moolenaar     static char_u qftitle_str[IOSIZE];
18468b62e310SBram Moolenaar 
18478b62e310SBram Moolenaar     vim_snprintf((char *)qftitle_str, IOSIZE, ":%s", (char *)cmd);
18488b62e310SBram Moolenaar     return qftitle_str;
18498b62e310SBram Moolenaar }
18508b62e310SBram Moolenaar 
18518b62e310SBram Moolenaar /*
18524aa47b28SBram Moolenaar  * Return a pointer to the current list in the specified quickfix stack
18534aa47b28SBram Moolenaar  */
18544aa47b28SBram Moolenaar     static qf_list_T *
qf_get_curlist(qf_info_T * qi)18554aa47b28SBram Moolenaar qf_get_curlist(qf_info_T *qi)
18564aa47b28SBram Moolenaar {
18570398e00aSBram Moolenaar     return qf_get_list(qi, qi->qf_curlist);
18584aa47b28SBram Moolenaar }
18594aa47b28SBram Moolenaar 
18604aa47b28SBram Moolenaar /*
186155b69264SBram Moolenaar  * Prepare for adding a new quickfix list. If the current list is in the
186255b69264SBram Moolenaar  * middle of the stack, then all the following lists are freed and then
186355b69264SBram Moolenaar  * the new list is added.
1864071d4279SBram Moolenaar  */
1865071d4279SBram Moolenaar     static void
qf_new_list(qf_info_T * qi,char_u * qf_title)186605540976SBram Moolenaar qf_new_list(qf_info_T *qi, char_u *qf_title)
1867071d4279SBram Moolenaar {
1868071d4279SBram Moolenaar     int		i;
1869108e7b42SBram Moolenaar     qf_list_T	*qfl;
1870071d4279SBram Moolenaar 
187100bf8cd2SBram Moolenaar     // If the current entry is not the last entry, delete entries beyond
187200bf8cd2SBram Moolenaar     // the current entry.  This makes it possible to browse in a tree-like
187332aa1020SBram Moolenaar     // way with ":grep".
1874d12f5c17SBram Moolenaar     while (qi->qf_listcount > qi->qf_curlist + 1)
1875fe15b7dfSBram Moolenaar 	qf_free(&qi->qf_lists[--qi->qf_listcount]);
1876071d4279SBram Moolenaar 
187700bf8cd2SBram Moolenaar     // When the stack is full, remove to oldest entry
187800bf8cd2SBram Moolenaar     // Otherwise, add a new entry.
1879d12f5c17SBram Moolenaar     if (qi->qf_listcount == LISTCOUNT)
1880071d4279SBram Moolenaar     {
1881fe15b7dfSBram Moolenaar 	qf_free(&qi->qf_lists[0]);
1882071d4279SBram Moolenaar 	for (i = 1; i < LISTCOUNT; ++i)
1883d12f5c17SBram Moolenaar 	    qi->qf_lists[i - 1] = qi->qf_lists[i];
1884d12f5c17SBram Moolenaar 	qi->qf_curlist = LISTCOUNT - 1;
1885071d4279SBram Moolenaar     }
1886071d4279SBram Moolenaar     else
1887d12f5c17SBram Moolenaar 	qi->qf_curlist = qi->qf_listcount++;
18884aa47b28SBram Moolenaar     qfl = qf_get_curlist(qi);
1889a80faa89SBram Moolenaar     CLEAR_POINTER(qfl);
1890108e7b42SBram Moolenaar     qf_store_title(qfl, qf_title);
18912d67d307SBram Moolenaar     qfl->qfl_type = qi->qfl_type;
1892108e7b42SBram Moolenaar     qfl->qf_id = ++last_qf_id;
1893071d4279SBram Moolenaar }
1894071d4279SBram Moolenaar 
1895d12f5c17SBram Moolenaar /*
18969f84ded3SBram Moolenaar  * Queue location list stack delete request.
18979f84ded3SBram Moolenaar  */
18989f84ded3SBram Moolenaar     static void
locstack_queue_delreq(qf_info_T * qi)18999f84ded3SBram Moolenaar locstack_queue_delreq(qf_info_T *qi)
19009f84ded3SBram Moolenaar {
19019f84ded3SBram Moolenaar     qf_delq_T	*q;
19029f84ded3SBram Moolenaar 
1903c799fe20SBram Moolenaar     q = ALLOC_ONE(qf_delq_T);
19049f84ded3SBram Moolenaar     if (q != NULL)
19059f84ded3SBram Moolenaar     {
19069f84ded3SBram Moolenaar 	q->qi = qi;
19079f84ded3SBram Moolenaar 	q->next = qf_delq_head;
19089f84ded3SBram Moolenaar 	qf_delq_head = q;
19099f84ded3SBram Moolenaar     }
19109f84ded3SBram Moolenaar }
19119f84ded3SBram Moolenaar 
19129f84ded3SBram Moolenaar /*
1913ee8188fcSBram Moolenaar  * Return the global quickfix stack window buffer number.
1914ee8188fcSBram Moolenaar  */
1915ee8188fcSBram Moolenaar     int
qf_stack_get_bufnr(void)1916ee8188fcSBram Moolenaar qf_stack_get_bufnr(void)
1917ee8188fcSBram Moolenaar {
1918ee8188fcSBram Moolenaar     return ql_info.qf_bufnr;
1919ee8188fcSBram Moolenaar }
1920ee8188fcSBram Moolenaar 
1921ee8188fcSBram Moolenaar /*
1922ee8188fcSBram Moolenaar  * Wipe the quickfix window buffer (if present) for the specified
1923ee8188fcSBram Moolenaar  * quickfix/location list.
1924ee8188fcSBram Moolenaar  */
1925ee8188fcSBram Moolenaar     static void
wipe_qf_buffer(qf_info_T * qi)1926ee8188fcSBram Moolenaar wipe_qf_buffer(qf_info_T *qi)
1927ee8188fcSBram Moolenaar {
1928ee8188fcSBram Moolenaar     buf_T	*qfbuf;
1929ee8188fcSBram Moolenaar 
1930ee8188fcSBram Moolenaar     if (qi->qf_bufnr != INVALID_QFBUFNR)
1931ee8188fcSBram Moolenaar     {
1932ee8188fcSBram Moolenaar 	qfbuf = buflist_findnr(qi->qf_bufnr);
1933ee8188fcSBram Moolenaar 	if (qfbuf != NULL && qfbuf->b_nwindows == 0)
1934ee8188fcSBram Moolenaar 	{
1935ee8188fcSBram Moolenaar 	    // If the quickfix buffer is not loaded in any window, then
1936ee8188fcSBram Moolenaar 	    // wipe the buffer.
1937a6e8f888SBram Moolenaar 	    close_buffer(NULL, qfbuf, DOBUF_WIPE, FALSE, FALSE);
1938ee8188fcSBram Moolenaar 	    qi->qf_bufnr = INVALID_QFBUFNR;
1939ee8188fcSBram Moolenaar 	}
1940ee8188fcSBram Moolenaar     }
1941ee8188fcSBram Moolenaar }
1942ee8188fcSBram Moolenaar 
1943ee8188fcSBram Moolenaar /*
1944fe15b7dfSBram Moolenaar  * Free a location list stack
1945d12f5c17SBram Moolenaar  */
1946d12f5c17SBram Moolenaar     static void
ll_free_all(qf_info_T ** pqi)194705540976SBram Moolenaar ll_free_all(qf_info_T **pqi)
1948f461c8e7SBram Moolenaar {
1949f461c8e7SBram Moolenaar     int		i;
1950d12f5c17SBram Moolenaar     qf_info_T	*qi;
1951f461c8e7SBram Moolenaar 
1952d12f5c17SBram Moolenaar     qi = *pqi;
1953d12f5c17SBram Moolenaar     if (qi == NULL)
1954d12f5c17SBram Moolenaar 	return;
195500bf8cd2SBram Moolenaar     *pqi = NULL;	// Remove reference to this list
1956d12f5c17SBram Moolenaar 
1957eeb1b9c7SBram Moolenaar     // If the location list is still in use, then queue the delete request
1958eeb1b9c7SBram Moolenaar     // to be processed later.
1959eeb1b9c7SBram Moolenaar     if (quickfix_busy > 0)
1960eeb1b9c7SBram Moolenaar     {
1961eeb1b9c7SBram Moolenaar 	locstack_queue_delreq(qi);
1962eeb1b9c7SBram Moolenaar 	return;
1963eeb1b9c7SBram Moolenaar     }
1964eeb1b9c7SBram Moolenaar 
1965d12f5c17SBram Moolenaar     qi->qf_refcount--;
1966d12f5c17SBram Moolenaar     if (qi->qf_refcount < 1)
1967d12f5c17SBram Moolenaar     {
19689f84ded3SBram Moolenaar 	// No references to this location list.
1969ee8188fcSBram Moolenaar 	// If the quickfix window buffer is loaded, then wipe it
1970ee8188fcSBram Moolenaar 	wipe_qf_buffer(qi);
1971ee8188fcSBram Moolenaar 
1972d12f5c17SBram Moolenaar 	for (i = 0; i < qi->qf_listcount; ++i)
19730398e00aSBram Moolenaar 	    qf_free(qf_get_list(qi, i));
1974d12f5c17SBram Moolenaar 	vim_free(qi);
1975f461c8e7SBram Moolenaar     }
1976d12f5c17SBram Moolenaar }
1977d12f5c17SBram Moolenaar 
197818cebf44SBram Moolenaar /*
197918cebf44SBram Moolenaar  * Free all the quickfix/location lists in the stack.
198018cebf44SBram Moolenaar  */
1981d12f5c17SBram Moolenaar     void
qf_free_all(win_T * wp)198205540976SBram Moolenaar qf_free_all(win_T *wp)
1983d12f5c17SBram Moolenaar {
1984d12f5c17SBram Moolenaar     int		i;
1985d12f5c17SBram Moolenaar     qf_info_T	*qi = &ql_info;
1986d12f5c17SBram Moolenaar 
1987d12f5c17SBram Moolenaar     if (wp != NULL)
1988d12f5c17SBram Moolenaar     {
198900bf8cd2SBram Moolenaar 	// location list
1990d12f5c17SBram Moolenaar 	ll_free_all(&wp->w_llist);
1991d12f5c17SBram Moolenaar 	ll_free_all(&wp->w_llist_ref);
1992d12f5c17SBram Moolenaar     }
1993d12f5c17SBram Moolenaar     else
199400bf8cd2SBram Moolenaar 	// quickfix list
1995d12f5c17SBram Moolenaar 	for (i = 0; i < qi->qf_listcount; ++i)
19960398e00aSBram Moolenaar 	    qf_free(qf_get_list(qi, i));
1997d12f5c17SBram Moolenaar }
1998f461c8e7SBram Moolenaar 
1999071d4279SBram Moolenaar /*
20009f84ded3SBram Moolenaar  * Delay freeing of location list stacks when the quickfix code is running.
20019f84ded3SBram Moolenaar  * Used to avoid problems with autocmds freeing location list stacks when the
20029f84ded3SBram Moolenaar  * quickfix code is still referencing the stack.
20039f84ded3SBram Moolenaar  * Must always call decr_quickfix_busy() exactly once after this.
20049f84ded3SBram Moolenaar  */
20059f84ded3SBram Moolenaar     static void
incr_quickfix_busy(void)20069f84ded3SBram Moolenaar incr_quickfix_busy(void)
20079f84ded3SBram Moolenaar {
20089f84ded3SBram Moolenaar     quickfix_busy++;
20099f84ded3SBram Moolenaar }
20109f84ded3SBram Moolenaar 
20119f84ded3SBram Moolenaar /*
20129f84ded3SBram Moolenaar  * Safe to free location list stacks. Process any delayed delete requests.
20139f84ded3SBram Moolenaar  */
20149f84ded3SBram Moolenaar     static void
decr_quickfix_busy(void)20159f84ded3SBram Moolenaar decr_quickfix_busy(void)
20169f84ded3SBram Moolenaar {
20179f84ded3SBram Moolenaar     if (--quickfix_busy == 0)
20189f84ded3SBram Moolenaar     {
20199f84ded3SBram Moolenaar 	// No longer referencing the location lists. Process all the pending
20209f84ded3SBram Moolenaar 	// delete requests.
20219f84ded3SBram Moolenaar 	while (qf_delq_head != NULL)
20229f84ded3SBram Moolenaar 	{
20239f84ded3SBram Moolenaar 	    qf_delq_T	*q = qf_delq_head;
20249f84ded3SBram Moolenaar 
20259f84ded3SBram Moolenaar 	    qf_delq_head = q->next;
20269f84ded3SBram Moolenaar 	    ll_free_all(&q->qi);
20279f84ded3SBram Moolenaar 	    vim_free(q);
20289f84ded3SBram Moolenaar 	}
20299f84ded3SBram Moolenaar     }
20309f84ded3SBram Moolenaar #ifdef ABORT_ON_INTERNAL_ERROR
20319f84ded3SBram Moolenaar     if (quickfix_busy < 0)
20329f84ded3SBram Moolenaar     {
2033f9e3e09fSBram Moolenaar 	emsg("quickfix_busy has become negative");
20349f84ded3SBram Moolenaar 	abort();
20359f84ded3SBram Moolenaar     }
20369f84ded3SBram Moolenaar #endif
20379f84ded3SBram Moolenaar }
20389f84ded3SBram Moolenaar 
20399f84ded3SBram Moolenaar #if defined(EXITFREE) || defined(PROTO)
20409f84ded3SBram Moolenaar     void
check_quickfix_busy(void)20419f84ded3SBram Moolenaar check_quickfix_busy(void)
20429f84ded3SBram Moolenaar {
20439f84ded3SBram Moolenaar     if (quickfix_busy != 0)
20449f84ded3SBram Moolenaar     {
2045f9e3e09fSBram Moolenaar 	semsg("quickfix_busy not zero on exit: %ld", (long)quickfix_busy);
20469f84ded3SBram Moolenaar # ifdef ABORT_ON_INTERNAL_ERROR
20479f84ded3SBram Moolenaar 	abort();
20489f84ded3SBram Moolenaar # endif
20499f84ded3SBram Moolenaar     }
20509f84ded3SBram Moolenaar }
20519f84ded3SBram Moolenaar #endif
20529f84ded3SBram Moolenaar 
20539f84ded3SBram Moolenaar /*
2054071d4279SBram Moolenaar  * Add an entry to the end of the list of errors.
205595946f12SBram Moolenaar  * Returns QF_OK or QF_FAIL.
2056071d4279SBram Moolenaar  */
2057071d4279SBram Moolenaar     static int
qf_add_entry(qf_list_T * qfl,char_u * dir,char_u * fname,char_u * module,int bufnum,char_u * mesg,long lnum,long end_lnum,int col,int end_col,int vis_col,char_u * pattern,int nr,int type,int valid)205805540976SBram Moolenaar qf_add_entry(
20590398e00aSBram Moolenaar     qf_list_T	*qfl,		// quickfix list entry
206000bf8cd2SBram Moolenaar     char_u	*dir,		// optional directory name
206100bf8cd2SBram Moolenaar     char_u	*fname,		// file name or NULL
206200bf8cd2SBram Moolenaar     char_u	*module,	// module name or NULL
206300bf8cd2SBram Moolenaar     int		bufnum,		// buffer number or zero
206400bf8cd2SBram Moolenaar     char_u	*mesg,		// message
206500bf8cd2SBram Moolenaar     long	lnum,		// line number
20666864efa5Sthinca     long	end_lnum,	// line number for end
206700bf8cd2SBram Moolenaar     int		col,		// column
20686864efa5Sthinca     int		end_col,	// column for end
206900bf8cd2SBram Moolenaar     int		vis_col,	// using visual column
207000bf8cd2SBram Moolenaar     char_u	*pattern,	// search pattern
207100bf8cd2SBram Moolenaar     int		nr,		// error number
207200bf8cd2SBram Moolenaar     int		type,		// type character
207300bf8cd2SBram Moolenaar     int		valid)		// valid entry
2074071d4279SBram Moolenaar {
207568b76a69SBram Moolenaar     qfline_T	*qfp;
207600bf8cd2SBram Moolenaar     qfline_T	**lastp;	// pointer to qf_last or NULL
2077071d4279SBram Moolenaar 
2078c799fe20SBram Moolenaar     if ((qfp = ALLOC_ONE(qfline_T)) == NULL)
207995946f12SBram Moolenaar 	return QF_FAIL;
208048b66fb5SBram Moolenaar     if (bufnum != 0)
20812f095a4bSBram Moolenaar     {
20822f095a4bSBram Moolenaar 	buf_T *buf = buflist_findnr(bufnum);
20832f095a4bSBram Moolenaar 
208448b66fb5SBram Moolenaar 	qfp->qf_fnum = bufnum;
20852f095a4bSBram Moolenaar 	if (buf != NULL)
2086c1542744SBram Moolenaar 	    buf->b_has_qf_entry |=
20872d67d307SBram Moolenaar 		IS_QF_LIST(qfl) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
20882f095a4bSBram Moolenaar     }
208948b66fb5SBram Moolenaar     else
20900398e00aSBram Moolenaar 	qfp->qf_fnum = qf_get_fnum(qfl, dir, fname);
2091071d4279SBram Moolenaar     if ((qfp->qf_text = vim_strsave(mesg)) == NULL)
2092071d4279SBram Moolenaar     {
2093071d4279SBram Moolenaar 	vim_free(qfp);
209495946f12SBram Moolenaar 	return QF_FAIL;
2095071d4279SBram Moolenaar     }
2096071d4279SBram Moolenaar     qfp->qf_lnum = lnum;
20976864efa5Sthinca     qfp->qf_end_lnum = end_lnum;
2098071d4279SBram Moolenaar     qfp->qf_col = col;
20996864efa5Sthinca     qfp->qf_end_col = end_col;
210005159a0cSBram Moolenaar     qfp->qf_viscol = vis_col;
210168b76a69SBram Moolenaar     if (pattern == NULL || *pattern == NUL)
210268b76a69SBram Moolenaar 	qfp->qf_pattern = NULL;
210368b76a69SBram Moolenaar     else if ((qfp->qf_pattern = vim_strsave(pattern)) == NULL)
210468b76a69SBram Moolenaar     {
210568b76a69SBram Moolenaar 	vim_free(qfp->qf_text);
210668b76a69SBram Moolenaar 	vim_free(qfp);
210795946f12SBram Moolenaar 	return QF_FAIL;
210868b76a69SBram Moolenaar     }
2109d76ce852SBram Moolenaar     if (module == NULL || *module == NUL)
2110d76ce852SBram Moolenaar 	qfp->qf_module = NULL;
2111d76ce852SBram Moolenaar     else if ((qfp->qf_module = vim_strsave(module)) == NULL)
2112d76ce852SBram Moolenaar     {
2113d76ce852SBram Moolenaar 	vim_free(qfp->qf_text);
2114d76ce852SBram Moolenaar 	vim_free(qfp->qf_pattern);
2115d76ce852SBram Moolenaar 	vim_free(qfp);
211695946f12SBram Moolenaar 	return QF_FAIL;
2117d76ce852SBram Moolenaar     }
2118071d4279SBram Moolenaar     qfp->qf_nr = nr;
211900bf8cd2SBram Moolenaar     if (type != 1 && !vim_isprintc(type)) // only printable chars allowed
2120071d4279SBram Moolenaar 	type = 0;
2121071d4279SBram Moolenaar     qfp->qf_type = type;
2122071d4279SBram Moolenaar     qfp->qf_valid = valid;
2123071d4279SBram Moolenaar 
2124fe15b7dfSBram Moolenaar     lastp = &qfl->qf_last;
21250398e00aSBram Moolenaar     if (qf_list_empty(qfl))		// first element in the list
2126071d4279SBram Moolenaar     {
2127fe15b7dfSBram Moolenaar 	qfl->qf_start = qfp;
2128fe15b7dfSBram Moolenaar 	qfl->qf_ptr = qfp;
2129fe15b7dfSBram Moolenaar 	qfl->qf_index = 0;
213083e6d7acSBram Moolenaar 	qfp->qf_prev = NULL;
2131071d4279SBram Moolenaar     }
2132071d4279SBram Moolenaar     else
2133071d4279SBram Moolenaar     {
213483e6d7acSBram Moolenaar 	qfp->qf_prev = *lastp;
213583e6d7acSBram Moolenaar 	(*lastp)->qf_next = qfp;
2136071d4279SBram Moolenaar     }
213783e6d7acSBram Moolenaar     qfp->qf_next = NULL;
2138071d4279SBram Moolenaar     qfp->qf_cleared = FALSE;
213983e6d7acSBram Moolenaar     *lastp = qfp;
2140fe15b7dfSBram Moolenaar     ++qfl->qf_count;
214100bf8cd2SBram Moolenaar     if (qfl->qf_index == 0 && qfp->qf_valid)	// first valid entry
2142071d4279SBram Moolenaar     {
2143fe15b7dfSBram Moolenaar 	qfl->qf_index = qfl->qf_count;
2144fe15b7dfSBram Moolenaar 	qfl->qf_ptr = qfp;
2145071d4279SBram Moolenaar     }
2146071d4279SBram Moolenaar 
214795946f12SBram Moolenaar     return QF_OK;
2148071d4279SBram Moolenaar }
2149071d4279SBram Moolenaar 
2150071d4279SBram Moolenaar /*
21512d67d307SBram Moolenaar  * Allocate a new quickfix/location list stack
2152d12f5c17SBram Moolenaar  */
21538b6144bdSBram Moolenaar     static qf_info_T *
qf_alloc_stack(qfltype_T qfltype)21542d67d307SBram Moolenaar qf_alloc_stack(qfltype_T qfltype)
2155d12f5c17SBram Moolenaar {
21568b6144bdSBram Moolenaar     qf_info_T *qi;
2157d12f5c17SBram Moolenaar 
2158c799fe20SBram Moolenaar     qi = ALLOC_CLEAR_ONE(qf_info_T);
21598b6144bdSBram Moolenaar     if (qi != NULL)
21602d67d307SBram Moolenaar     {
21618b6144bdSBram Moolenaar 	qi->qf_refcount++;
21622d67d307SBram Moolenaar 	qi->qfl_type = qfltype;
2163ee8188fcSBram Moolenaar 	qi->qf_bufnr = INVALID_QFBUFNR;
21642d67d307SBram Moolenaar     }
21658b6144bdSBram Moolenaar     return qi;
2166d12f5c17SBram Moolenaar }
2167d12f5c17SBram Moolenaar 
2168d12f5c17SBram Moolenaar /*
2169fe15b7dfSBram Moolenaar  * Return the location list stack for window 'wp'.
2170fe15b7dfSBram Moolenaar  * If not present, allocate a location list stack
2171d12f5c17SBram Moolenaar  */
2172d12f5c17SBram Moolenaar     static qf_info_T *
ll_get_or_alloc_list(win_T * wp)217305540976SBram Moolenaar ll_get_or_alloc_list(win_T *wp)
2174d12f5c17SBram Moolenaar {
2175d12f5c17SBram Moolenaar     if (IS_LL_WINDOW(wp))
217600bf8cd2SBram Moolenaar 	// For a location list window, use the referenced location list
2177d12f5c17SBram Moolenaar 	return wp->w_llist_ref;
2178d12f5c17SBram Moolenaar 
217900bf8cd2SBram Moolenaar     // For a non-location list window, w_llist_ref should not point to a
218000bf8cd2SBram Moolenaar     // location list.
2181d12f5c17SBram Moolenaar     ll_free_all(&wp->w_llist_ref);
2182d12f5c17SBram Moolenaar 
2183d12f5c17SBram Moolenaar     if (wp->w_llist == NULL)
21842d67d307SBram Moolenaar 	wp->w_llist = qf_alloc_stack(QFLT_LOCATION);	// new location list
2185d12f5c17SBram Moolenaar     return wp->w_llist;
2186d12f5c17SBram Moolenaar }
2187d12f5c17SBram Moolenaar 
2188d12f5c17SBram Moolenaar /*
218987f59b09SBram Moolenaar  * Get the quickfix/location list stack to use for the specified Ex command.
219087f59b09SBram Moolenaar  * For a location list command, returns the stack for the current window.  If
219187f59b09SBram Moolenaar  * the location list is not found, then returns NULL and prints an error
219287f59b09SBram Moolenaar  * message if 'print_emsg' is TRUE.
219387f59b09SBram Moolenaar  */
219487f59b09SBram Moolenaar     static qf_info_T *
qf_cmd_get_stack(exarg_T * eap,int print_emsg)219587f59b09SBram Moolenaar qf_cmd_get_stack(exarg_T *eap, int print_emsg)
219687f59b09SBram Moolenaar {
219787f59b09SBram Moolenaar     qf_info_T	*qi = &ql_info;
219887f59b09SBram Moolenaar 
219987f59b09SBram Moolenaar     if (is_loclist_cmd(eap->cmdidx))
220087f59b09SBram Moolenaar     {
220187f59b09SBram Moolenaar 	qi = GET_LOC_LIST(curwin);
220287f59b09SBram Moolenaar 	if (qi == NULL)
220387f59b09SBram Moolenaar 	{
220487f59b09SBram Moolenaar 	    if (print_emsg)
220587f59b09SBram Moolenaar 		emsg(_(e_loclist));
220687f59b09SBram Moolenaar 	    return NULL;
220787f59b09SBram Moolenaar 	}
220887f59b09SBram Moolenaar     }
220987f59b09SBram Moolenaar 
221087f59b09SBram Moolenaar     return qi;
221187f59b09SBram Moolenaar }
221287f59b09SBram Moolenaar 
221387f59b09SBram Moolenaar /*
221487f59b09SBram Moolenaar  * Get the quickfix/location list stack to use for the specified Ex command.
221587f59b09SBram Moolenaar  * For a location list command, returns the stack for the current window.
221687f59b09SBram Moolenaar  * If the location list is not present, then allocates a new one.
221787f59b09SBram Moolenaar  * Returns NULL if the allocation fails.  For a location list command, sets
221887f59b09SBram Moolenaar  * 'pwinp' to curwin.
221987f59b09SBram Moolenaar  */
222087f59b09SBram Moolenaar     static qf_info_T *
qf_cmd_get_or_alloc_stack(exarg_T * eap,win_T ** pwinp)222187f59b09SBram Moolenaar qf_cmd_get_or_alloc_stack(exarg_T *eap, win_T **pwinp)
222287f59b09SBram Moolenaar {
222387f59b09SBram Moolenaar     qf_info_T	*qi = &ql_info;
222487f59b09SBram Moolenaar 
222587f59b09SBram Moolenaar     if (is_loclist_cmd(eap->cmdidx))
222687f59b09SBram Moolenaar     {
222787f59b09SBram Moolenaar 	qi = ll_get_or_alloc_list(curwin);
222887f59b09SBram Moolenaar 	if (qi == NULL)
222987f59b09SBram Moolenaar 	    return NULL;
223087f59b09SBram Moolenaar 	*pwinp = curwin;
223187f59b09SBram Moolenaar     }
223287f59b09SBram Moolenaar 
223387f59b09SBram Moolenaar     return qi;
223487f59b09SBram Moolenaar }
223587f59b09SBram Moolenaar 
223687f59b09SBram Moolenaar /*
223709037503SBram Moolenaar  * Copy location list entries from 'from_qfl' to 'to_qfl'.
2238d12f5c17SBram Moolenaar  */
223909037503SBram Moolenaar     static int
copy_loclist_entries(qf_list_T * from_qfl,qf_list_T * to_qfl)22400398e00aSBram Moolenaar copy_loclist_entries(qf_list_T *from_qfl, qf_list_T *to_qfl)
2241d12f5c17SBram Moolenaar {
2242d12f5c17SBram Moolenaar     int		i;
224309037503SBram Moolenaar     qfline_T    *from_qfp;
224409037503SBram Moolenaar     qfline_T    *prevp;
224509037503SBram Moolenaar 
224609037503SBram Moolenaar     // copy all the location entries in this list
2247a16123a6SBram Moolenaar     FOR_ALL_QFL_ITEMS(from_qfl, from_qfp, i)
224809037503SBram Moolenaar     {
22490398e00aSBram Moolenaar 	if (qf_add_entry(to_qfl,
225009037503SBram Moolenaar 		    NULL,
225109037503SBram Moolenaar 		    NULL,
225209037503SBram Moolenaar 		    from_qfp->qf_module,
225309037503SBram Moolenaar 		    0,
225409037503SBram Moolenaar 		    from_qfp->qf_text,
225509037503SBram Moolenaar 		    from_qfp->qf_lnum,
22566864efa5Sthinca 		    from_qfp->qf_end_lnum,
225709037503SBram Moolenaar 		    from_qfp->qf_col,
22586864efa5Sthinca 		    from_qfp->qf_end_col,
225909037503SBram Moolenaar 		    from_qfp->qf_viscol,
226009037503SBram Moolenaar 		    from_qfp->qf_pattern,
226109037503SBram Moolenaar 		    from_qfp->qf_nr,
226209037503SBram Moolenaar 		    0,
226395946f12SBram Moolenaar 		    from_qfp->qf_valid) == QF_FAIL)
226409037503SBram Moolenaar 	    return FAIL;
226509037503SBram Moolenaar 
226609037503SBram Moolenaar 	// qf_add_entry() will not set the qf_num field, as the
226709037503SBram Moolenaar 	// directory and file names are not supplied. So the qf_fnum
226809037503SBram Moolenaar 	// field is copied here.
226909037503SBram Moolenaar 	prevp = to_qfl->qf_last;
227009037503SBram Moolenaar 	prevp->qf_fnum = from_qfp->qf_fnum;	// file number
227109037503SBram Moolenaar 	prevp->qf_type = from_qfp->qf_type;	// error type
227209037503SBram Moolenaar 	if (from_qfl->qf_ptr == from_qfp)
227309037503SBram Moolenaar 	    to_qfl->qf_ptr = prevp;		// current location
227409037503SBram Moolenaar     }
227509037503SBram Moolenaar 
227609037503SBram Moolenaar     return OK;
227709037503SBram Moolenaar }
2278d12f5c17SBram Moolenaar 
2279d12f5c17SBram Moolenaar /*
228009037503SBram Moolenaar  * Copy the specified location list 'from_qfl' to 'to_qfl'.
2281d12f5c17SBram Moolenaar  */
228209037503SBram Moolenaar     static int
copy_loclist(qf_list_T * from_qfl,qf_list_T * to_qfl)22830398e00aSBram Moolenaar copy_loclist(qf_list_T *from_qfl, qf_list_T *to_qfl)
2284d12f5c17SBram Moolenaar {
228509037503SBram Moolenaar     // Some of the fields are populated by qf_add_entry()
22862d67d307SBram Moolenaar     to_qfl->qfl_type = from_qfl->qfl_type;
2287d12f5c17SBram Moolenaar     to_qfl->qf_nonevalid = from_qfl->qf_nonevalid;
2288d12f5c17SBram Moolenaar     to_qfl->qf_count = 0;
2289d12f5c17SBram Moolenaar     to_qfl->qf_index = 0;
2290d12f5c17SBram Moolenaar     to_qfl->qf_start = NULL;
229183e6d7acSBram Moolenaar     to_qfl->qf_last = NULL;
2292d12f5c17SBram Moolenaar     to_qfl->qf_ptr = NULL;
22937fd73200SBram Moolenaar     if (from_qfl->qf_title != NULL)
22947fd73200SBram Moolenaar 	to_qfl->qf_title = vim_strsave(from_qfl->qf_title);
22957fd73200SBram Moolenaar     else
22967fd73200SBram Moolenaar 	to_qfl->qf_title = NULL;
22978f77c5a4SBram Moolenaar     if (from_qfl->qf_ctx != NULL)
22988f77c5a4SBram Moolenaar     {
22998f77c5a4SBram Moolenaar 	to_qfl->qf_ctx = alloc_tv();
23008f77c5a4SBram Moolenaar 	if (to_qfl->qf_ctx != NULL)
23018f77c5a4SBram Moolenaar 	    copy_tv(from_qfl->qf_ctx, to_qfl->qf_ctx);
23028f77c5a4SBram Moolenaar     }
23038f77c5a4SBram Moolenaar     else
23048f77c5a4SBram Moolenaar 	to_qfl->qf_ctx = NULL;
2305d43906d2SBram Moolenaar     if (from_qfl->qftf_cb.cb_name != NULL)
2306d43906d2SBram Moolenaar 	copy_callback(&to_qfl->qftf_cb, &from_qfl->qftf_cb);
2307858ba06dSBram Moolenaar     else
2308d43906d2SBram Moolenaar 	to_qfl->qftf_cb.cb_name = NULL;
2309d12f5c17SBram Moolenaar 
2310d12f5c17SBram Moolenaar     if (from_qfl->qf_count)
23110398e00aSBram Moolenaar 	if (copy_loclist_entries(from_qfl, to_qfl) == FAIL)
231209037503SBram Moolenaar 	    return FAIL;
2313d12f5c17SBram Moolenaar 
231409037503SBram Moolenaar     to_qfl->qf_index = from_qfl->qf_index;	// current index in the list
2315d12f5c17SBram Moolenaar 
231609037503SBram Moolenaar     // Assign a new ID for the location list
2317a539f4f1SBram Moolenaar     to_qfl->qf_id = ++last_qf_id;
2318b254af31SBram Moolenaar     to_qfl->qf_changedtick = 0L;
2319a539f4f1SBram Moolenaar 
232009037503SBram Moolenaar     // When no valid entries are present in the list, qf_ptr points to
232109037503SBram Moolenaar     // the first item in the list
2322d236ac0dSBram Moolenaar     if (to_qfl->qf_nonevalid)
2323730d2c07SBram Moolenaar     {
2324d12f5c17SBram Moolenaar 	to_qfl->qf_ptr = to_qfl->qf_start;
2325730d2c07SBram Moolenaar 	to_qfl->qf_index = 1;
2326730d2c07SBram Moolenaar     }
232709037503SBram Moolenaar 
232809037503SBram Moolenaar     return OK;
2329d12f5c17SBram Moolenaar }
2330d12f5c17SBram Moolenaar 
233109037503SBram Moolenaar /*
233209037503SBram Moolenaar  * Copy the location list stack 'from' window to 'to' window.
233309037503SBram Moolenaar  */
233409037503SBram Moolenaar     void
copy_loclist_stack(win_T * from,win_T * to)233509037503SBram Moolenaar copy_loclist_stack(win_T *from, win_T *to)
233609037503SBram Moolenaar {
233709037503SBram Moolenaar     qf_info_T	*qi;
233809037503SBram Moolenaar     int		idx;
233909037503SBram Moolenaar 
234009037503SBram Moolenaar     // When copying from a location list window, copy the referenced
234109037503SBram Moolenaar     // location list. For other windows, copy the location list for
234209037503SBram Moolenaar     // that window.
234309037503SBram Moolenaar     if (IS_LL_WINDOW(from))
234409037503SBram Moolenaar 	qi = from->w_llist_ref;
234509037503SBram Moolenaar     else
234609037503SBram Moolenaar 	qi = from->w_llist;
234709037503SBram Moolenaar 
234809037503SBram Moolenaar     if (qi == NULL)		    // no location list to copy
234909037503SBram Moolenaar 	return;
235009037503SBram Moolenaar 
235109037503SBram Moolenaar     // allocate a new location list
23522d67d307SBram Moolenaar     if ((to->w_llist = qf_alloc_stack(QFLT_LOCATION)) == NULL)
235309037503SBram Moolenaar 	return;
235409037503SBram Moolenaar 
235509037503SBram Moolenaar     to->w_llist->qf_listcount = qi->qf_listcount;
235609037503SBram Moolenaar 
235709037503SBram Moolenaar     // Copy the location lists one at a time
235809037503SBram Moolenaar     for (idx = 0; idx < qi->qf_listcount; ++idx)
235909037503SBram Moolenaar     {
236009037503SBram Moolenaar 	to->w_llist->qf_curlist = idx;
236109037503SBram Moolenaar 
23620398e00aSBram Moolenaar 	if (copy_loclist(qf_get_list(qi, idx),
23630398e00aSBram Moolenaar 			qf_get_list(to->w_llist, idx)) == FAIL)
236409037503SBram Moolenaar 	{
236509037503SBram Moolenaar 	    qf_free_all(to);
236609037503SBram Moolenaar 	    return;
236709037503SBram Moolenaar 	}
236809037503SBram Moolenaar     }
236909037503SBram Moolenaar 
237009037503SBram Moolenaar     to->w_llist->qf_curlist = qi->qf_curlist;	// current list
2371d12f5c17SBram Moolenaar }
2372d12f5c17SBram Moolenaar 
2373d12f5c17SBram Moolenaar /*
23747618e00dSBram Moolenaar  * Get buffer number for file "directory/fname".
23752f095a4bSBram Moolenaar  * Also sets the b_has_qf_entry flag.
2376071d4279SBram Moolenaar  */
2377071d4279SBram Moolenaar     static int
qf_get_fnum(qf_list_T * qfl,char_u * directory,char_u * fname)23780398e00aSBram Moolenaar qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname)
2379071d4279SBram Moolenaar {
23808240433fSBram Moolenaar     char_u	*ptr = NULL;
23812f095a4bSBram Moolenaar     buf_T	*buf;
23828240433fSBram Moolenaar     char_u	*bufname;
23832f095a4bSBram Moolenaar 
238400bf8cd2SBram Moolenaar     if (fname == NULL || *fname == NUL)		// no file name
2385071d4279SBram Moolenaar 	return 0;
2386071d4279SBram Moolenaar 
2387071d4279SBram Moolenaar #ifdef VMS
2388071d4279SBram Moolenaar     vms_remove_version(fname);
2389071d4279SBram Moolenaar #endif
2390071d4279SBram Moolenaar #ifdef BACKSLASH_IN_FILENAME
2391071d4279SBram Moolenaar     if (directory != NULL)
2392071d4279SBram Moolenaar 	slash_adjust(directory);
2393071d4279SBram Moolenaar     slash_adjust(fname);
2394071d4279SBram Moolenaar #endif
2395071d4279SBram Moolenaar     if (directory != NULL && !vim_isAbsName(fname)
2396071d4279SBram Moolenaar 	    && (ptr = concat_fnames(directory, fname, TRUE)) != NULL)
2397071d4279SBram Moolenaar     {
239800bf8cd2SBram Moolenaar 	// Here we check if the file really exists.
239900bf8cd2SBram Moolenaar 	// This should normally be true, but if make works without
240000bf8cd2SBram Moolenaar 	// "leaving directory"-messages we might have missed a
240100bf8cd2SBram Moolenaar 	// directory change.
2402071d4279SBram Moolenaar 	if (mch_getperm(ptr) < 0)
2403071d4279SBram Moolenaar 	{
2404071d4279SBram Moolenaar 	    vim_free(ptr);
2405108e7b42SBram Moolenaar 	    directory = qf_guess_filepath(qfl, fname);
2406071d4279SBram Moolenaar 	    if (directory)
2407071d4279SBram Moolenaar 		ptr = concat_fnames(directory, fname, TRUE);
2408071d4279SBram Moolenaar 	    else
2409071d4279SBram Moolenaar 		ptr = vim_strsave(fname);
2410071d4279SBram Moolenaar 	}
241100bf8cd2SBram Moolenaar 	// Use concatenated directory name and file name
24128240433fSBram Moolenaar 	bufname = ptr;
24138240433fSBram Moolenaar     }
24148240433fSBram Moolenaar     else
24158240433fSBram Moolenaar 	bufname = fname;
24168240433fSBram Moolenaar 
24178240433fSBram Moolenaar     if (qf_last_bufname != NULL && STRCMP(bufname, qf_last_bufname) == 0
2418b25f9a97SBram Moolenaar 	    && bufref_valid(&qf_last_bufref))
24198240433fSBram Moolenaar     {
2420b25f9a97SBram Moolenaar 	buf = qf_last_bufref.br_buf;
2421071d4279SBram Moolenaar 	vim_free(ptr);
2422071d4279SBram Moolenaar     }
24232f095a4bSBram Moolenaar     else
24248240433fSBram Moolenaar     {
24258240433fSBram Moolenaar 	vim_free(qf_last_bufname);
24268240433fSBram Moolenaar 	buf = buflist_new(bufname, NULL, (linenr_T)0, BLN_NOOPT);
24278240433fSBram Moolenaar 	if (bufname == ptr)
24288240433fSBram Moolenaar 	    qf_last_bufname = bufname;
24298240433fSBram Moolenaar 	else
24308240433fSBram Moolenaar 	    qf_last_bufname = vim_strsave(bufname);
2431b25f9a97SBram Moolenaar 	set_bufref(&qf_last_bufref, buf);
24328240433fSBram Moolenaar     }
24332f095a4bSBram Moolenaar     if (buf == NULL)
24342f095a4bSBram Moolenaar 	return 0;
24358240433fSBram Moolenaar 
2436c1542744SBram Moolenaar     buf->b_has_qf_entry =
24372d67d307SBram Moolenaar 			IS_QF_LIST(qfl) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
24382f095a4bSBram Moolenaar     return buf->b_fnum;
2439071d4279SBram Moolenaar }
2440071d4279SBram Moolenaar 
2441071d4279SBram Moolenaar /*
244238df43bdSBram Moolenaar  * Push dirbuf onto the directory stack and return pointer to actual dir or
244338df43bdSBram Moolenaar  * NULL on error.
2444071d4279SBram Moolenaar  */
2445071d4279SBram Moolenaar     static char_u *
qf_push_dir(char_u * dirbuf,struct dir_stack_T ** stackptr,int is_file_stack)2446361c8f0eSBram Moolenaar qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, int is_file_stack)
2447071d4279SBram Moolenaar {
2448071d4279SBram Moolenaar     struct dir_stack_T  *ds_new;
2449071d4279SBram Moolenaar     struct dir_stack_T  *ds_ptr;
2450071d4279SBram Moolenaar 
245100bf8cd2SBram Moolenaar     // allocate new stack element and hook it in
2452c799fe20SBram Moolenaar     ds_new = ALLOC_ONE(struct dir_stack_T);
2453071d4279SBram Moolenaar     if (ds_new == NULL)
2454071d4279SBram Moolenaar 	return NULL;
2455071d4279SBram Moolenaar 
2456071d4279SBram Moolenaar     ds_new->next = *stackptr;
2457071d4279SBram Moolenaar     *stackptr = ds_new;
2458071d4279SBram Moolenaar 
245900bf8cd2SBram Moolenaar     // store directory on the stack
2460071d4279SBram Moolenaar     if (vim_isAbsName(dirbuf)
2461071d4279SBram Moolenaar 	    || (*stackptr)->next == NULL
2462361c8f0eSBram Moolenaar 	    || (*stackptr && is_file_stack))
2463071d4279SBram Moolenaar 	(*stackptr)->dirname = vim_strsave(dirbuf);
2464071d4279SBram Moolenaar     else
2465071d4279SBram Moolenaar     {
246600bf8cd2SBram Moolenaar 	// Okay we don't have an absolute path.
246700bf8cd2SBram Moolenaar 	// dirbuf must be a subdir of one of the directories on the stack.
246800bf8cd2SBram Moolenaar 	// Let's search...
2469071d4279SBram Moolenaar 	ds_new = (*stackptr)->next;
2470071d4279SBram Moolenaar 	(*stackptr)->dirname = NULL;
2471071d4279SBram Moolenaar 	while (ds_new)
2472071d4279SBram Moolenaar 	{
2473071d4279SBram Moolenaar 	    vim_free((*stackptr)->dirname);
2474071d4279SBram Moolenaar 	    (*stackptr)->dirname = concat_fnames(ds_new->dirname, dirbuf,
2475071d4279SBram Moolenaar 		    TRUE);
2476071d4279SBram Moolenaar 	    if (mch_isdir((*stackptr)->dirname) == TRUE)
2477071d4279SBram Moolenaar 		break;
2478071d4279SBram Moolenaar 
2479071d4279SBram Moolenaar 	    ds_new = ds_new->next;
2480071d4279SBram Moolenaar 	}
2481071d4279SBram Moolenaar 
248200bf8cd2SBram Moolenaar 	// clean up all dirs we already left
2483071d4279SBram Moolenaar 	while ((*stackptr)->next != ds_new)
2484071d4279SBram Moolenaar 	{
2485071d4279SBram Moolenaar 	    ds_ptr = (*stackptr)->next;
2486071d4279SBram Moolenaar 	    (*stackptr)->next = (*stackptr)->next->next;
2487071d4279SBram Moolenaar 	    vim_free(ds_ptr->dirname);
2488071d4279SBram Moolenaar 	    vim_free(ds_ptr);
2489071d4279SBram Moolenaar 	}
2490071d4279SBram Moolenaar 
249100bf8cd2SBram Moolenaar 	// Nothing found -> it must be on top level
2492071d4279SBram Moolenaar 	if (ds_new == NULL)
2493071d4279SBram Moolenaar 	{
2494071d4279SBram Moolenaar 	    vim_free((*stackptr)->dirname);
2495071d4279SBram Moolenaar 	    (*stackptr)->dirname = vim_strsave(dirbuf);
2496071d4279SBram Moolenaar 	}
2497071d4279SBram Moolenaar     }
2498071d4279SBram Moolenaar 
2499071d4279SBram Moolenaar     if ((*stackptr)->dirname != NULL)
2500071d4279SBram Moolenaar 	return (*stackptr)->dirname;
2501071d4279SBram Moolenaar     else
2502071d4279SBram Moolenaar     {
2503071d4279SBram Moolenaar 	ds_ptr = *stackptr;
2504071d4279SBram Moolenaar 	*stackptr = (*stackptr)->next;
2505071d4279SBram Moolenaar 	vim_free(ds_ptr);
2506071d4279SBram Moolenaar 	return NULL;
2507071d4279SBram Moolenaar     }
2508071d4279SBram Moolenaar }
2509071d4279SBram Moolenaar 
2510071d4279SBram Moolenaar /*
2511071d4279SBram Moolenaar  * pop dirbuf from the directory stack and return previous directory or NULL if
2512071d4279SBram Moolenaar  * stack is empty
2513071d4279SBram Moolenaar  */
2514071d4279SBram Moolenaar     static char_u *
qf_pop_dir(struct dir_stack_T ** stackptr)251505540976SBram Moolenaar qf_pop_dir(struct dir_stack_T **stackptr)
2516071d4279SBram Moolenaar {
2517071d4279SBram Moolenaar     struct dir_stack_T  *ds_ptr;
2518071d4279SBram Moolenaar 
251900bf8cd2SBram Moolenaar     // TODO: Should we check if dirbuf is the directory on top of the stack?
252000bf8cd2SBram Moolenaar     // What to do if it isn't?
2521071d4279SBram Moolenaar 
252200bf8cd2SBram Moolenaar     // pop top element and free it
2523071d4279SBram Moolenaar     if (*stackptr != NULL)
2524071d4279SBram Moolenaar     {
2525071d4279SBram Moolenaar 	ds_ptr = *stackptr;
2526071d4279SBram Moolenaar 	*stackptr = (*stackptr)->next;
2527071d4279SBram Moolenaar 	vim_free(ds_ptr->dirname);
2528071d4279SBram Moolenaar 	vim_free(ds_ptr);
2529071d4279SBram Moolenaar     }
2530071d4279SBram Moolenaar 
253100bf8cd2SBram Moolenaar     // return NEW top element as current dir or NULL if stack is empty
2532071d4279SBram Moolenaar     return *stackptr ? (*stackptr)->dirname : NULL;
2533071d4279SBram Moolenaar }
2534071d4279SBram Moolenaar 
2535071d4279SBram Moolenaar /*
2536071d4279SBram Moolenaar  * clean up directory stack
2537071d4279SBram Moolenaar  */
2538071d4279SBram Moolenaar     static void
qf_clean_dir_stack(struct dir_stack_T ** stackptr)253905540976SBram Moolenaar qf_clean_dir_stack(struct dir_stack_T **stackptr)
2540071d4279SBram Moolenaar {
2541071d4279SBram Moolenaar     struct dir_stack_T  *ds_ptr;
2542071d4279SBram Moolenaar 
2543071d4279SBram Moolenaar     while ((ds_ptr = *stackptr) != NULL)
2544071d4279SBram Moolenaar     {
2545071d4279SBram Moolenaar 	*stackptr = (*stackptr)->next;
2546071d4279SBram Moolenaar 	vim_free(ds_ptr->dirname);
2547071d4279SBram Moolenaar 	vim_free(ds_ptr);
2548071d4279SBram Moolenaar     }
2549071d4279SBram Moolenaar }
2550071d4279SBram Moolenaar 
2551071d4279SBram Moolenaar /*
2552071d4279SBram Moolenaar  * Check in which directory of the directory stack the given file can be
2553071d4279SBram Moolenaar  * found.
2554aa23b379SBram Moolenaar  * Returns a pointer to the directory name or NULL if not found.
2555071d4279SBram Moolenaar  * Cleans up intermediate directory entries.
2556071d4279SBram Moolenaar  *
2557071d4279SBram Moolenaar  * TODO: How to solve the following problem?
25587a2b0e55SBram Moolenaar  * If we have this directory tree:
2559071d4279SBram Moolenaar  *     ./
2560071d4279SBram Moolenaar  *     ./aa
2561071d4279SBram Moolenaar  *     ./aa/bb
2562071d4279SBram Moolenaar  *     ./bb
2563071d4279SBram Moolenaar  *     ./bb/x.c
2564071d4279SBram Moolenaar  * and make says:
2565071d4279SBram Moolenaar  *     making all in aa
2566071d4279SBram Moolenaar  *     making all in bb
2567071d4279SBram Moolenaar  *     x.c:9: Error
2568071d4279SBram Moolenaar  * Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb.
2569071d4279SBram Moolenaar  * qf_guess_filepath will return NULL.
2570071d4279SBram Moolenaar  */
2571071d4279SBram Moolenaar     static char_u *
qf_guess_filepath(qf_list_T * qfl,char_u * filename)2572fe15b7dfSBram Moolenaar qf_guess_filepath(qf_list_T *qfl, char_u *filename)
2573071d4279SBram Moolenaar {
2574071d4279SBram Moolenaar     struct dir_stack_T     *ds_ptr;
2575071d4279SBram Moolenaar     struct dir_stack_T     *ds_tmp;
2576071d4279SBram Moolenaar     char_u		   *fullname;
2577071d4279SBram Moolenaar 
257800bf8cd2SBram Moolenaar     // no dirs on the stack - there's nothing we can do
2579a7df8c70SBram Moolenaar     if (qfl->qf_dir_stack == NULL)
2580071d4279SBram Moolenaar 	return NULL;
2581071d4279SBram Moolenaar 
2582a7df8c70SBram Moolenaar     ds_ptr = qfl->qf_dir_stack->next;
2583071d4279SBram Moolenaar     fullname = NULL;
2584071d4279SBram Moolenaar     while (ds_ptr)
2585071d4279SBram Moolenaar     {
2586071d4279SBram Moolenaar 	vim_free(fullname);
2587071d4279SBram Moolenaar 	fullname = concat_fnames(ds_ptr->dirname, filename, TRUE);
2588071d4279SBram Moolenaar 
258900bf8cd2SBram Moolenaar 	// If concat_fnames failed, just go on. The worst thing that can happen
259000bf8cd2SBram Moolenaar 	// is that we delete the entire stack.
2591071d4279SBram Moolenaar 	if ((fullname != NULL) && (mch_getperm(fullname) >= 0))
2592071d4279SBram Moolenaar 	    break;
2593071d4279SBram Moolenaar 
2594071d4279SBram Moolenaar 	ds_ptr = ds_ptr->next;
2595071d4279SBram Moolenaar     }
2596071d4279SBram Moolenaar 
2597071d4279SBram Moolenaar     vim_free(fullname);
2598071d4279SBram Moolenaar 
259900bf8cd2SBram Moolenaar     // clean up all dirs we already left
2600a7df8c70SBram Moolenaar     while (qfl->qf_dir_stack->next != ds_ptr)
2601071d4279SBram Moolenaar     {
2602a7df8c70SBram Moolenaar 	ds_tmp = qfl->qf_dir_stack->next;
2603a7df8c70SBram Moolenaar 	qfl->qf_dir_stack->next = qfl->qf_dir_stack->next->next;
2604071d4279SBram Moolenaar 	vim_free(ds_tmp->dirname);
2605071d4279SBram Moolenaar 	vim_free(ds_tmp);
2606071d4279SBram Moolenaar     }
2607071d4279SBram Moolenaar 
2608071d4279SBram Moolenaar     return ds_ptr == NULL ? NULL : ds_ptr->dirname;
2609071d4279SBram Moolenaar }
2610071d4279SBram Moolenaar 
2611071d4279SBram Moolenaar /*
26123c097226SBram Moolenaar  * Returns TRUE if a quickfix/location list with the given identifier exists.
26133c097226SBram Moolenaar  */
26143c097226SBram Moolenaar     static int
qflist_valid(win_T * wp,int_u qf_id)26153c097226SBram Moolenaar qflist_valid(win_T *wp, int_u qf_id)
26163c097226SBram Moolenaar {
26173c097226SBram Moolenaar     qf_info_T	*qi = &ql_info;
26183c097226SBram Moolenaar     int		i;
26193c097226SBram Moolenaar 
26203c097226SBram Moolenaar     if (wp != NULL)
26213c097226SBram Moolenaar     {
26222c7080bfSBram Moolenaar 	if (!win_valid(wp))
26232c7080bfSBram Moolenaar 	    return FALSE;
262400bf8cd2SBram Moolenaar 	qi = GET_LOC_LIST(wp);	    // Location list
26253c097226SBram Moolenaar 	if (qi == NULL)
26263c097226SBram Moolenaar 	    return FALSE;
26273c097226SBram Moolenaar     }
26283c097226SBram Moolenaar 
26293c097226SBram Moolenaar     for (i = 0; i < qi->qf_listcount; ++i)
26303c097226SBram Moolenaar 	if (qi->qf_lists[i].qf_id == qf_id)
26313c097226SBram Moolenaar 	    return TRUE;
26323c097226SBram Moolenaar 
26333c097226SBram Moolenaar     return FALSE;
26343c097226SBram Moolenaar }
26353c097226SBram Moolenaar 
26363c097226SBram Moolenaar /*
2637ffec3c53SBram Moolenaar  * When loading a file from the quickfix, the autocommands may modify it.
2638ffec3c53SBram Moolenaar  * This may invalidate the current quickfix entry.  This function checks
26397a2b0e55SBram Moolenaar  * whether an entry is still present in the quickfix list.
2640ffec3c53SBram Moolenaar  * Similar to location list.
2641ffec3c53SBram Moolenaar  */
2642ffec3c53SBram Moolenaar     static int
is_qf_entry_present(qf_list_T * qfl,qfline_T * qf_ptr)2643fe15b7dfSBram Moolenaar is_qf_entry_present(qf_list_T *qfl, qfline_T *qf_ptr)
2644ffec3c53SBram Moolenaar {
2645ffec3c53SBram Moolenaar     qfline_T	*qfp;
2646ffec3c53SBram Moolenaar     int		i;
2647ffec3c53SBram Moolenaar 
264800bf8cd2SBram Moolenaar     // Search for the entry in the current list
2649a16123a6SBram Moolenaar     FOR_ALL_QFL_ITEMS(qfl, qfp, i)
2650a16123a6SBram Moolenaar 	if (qfp == qf_ptr)
2651ffec3c53SBram Moolenaar 	    break;
2652ffec3c53SBram Moolenaar 
265395946f12SBram Moolenaar     if (i > qfl->qf_count) // Entry is not found
2654ffec3c53SBram Moolenaar 	return FALSE;
2655ffec3c53SBram Moolenaar 
2656ffec3c53SBram Moolenaar     return TRUE;
2657ffec3c53SBram Moolenaar }
2658ffec3c53SBram Moolenaar 
2659ffec3c53SBram Moolenaar /*
2660ef6b8de4SBram Moolenaar  * Get the next valid entry in the current quickfix/location list. The search
26619cb03716SBram Moolenaar  * starts from the current entry.  Returns NULL on failure.
2662ef6b8de4SBram Moolenaar  */
2663ef6b8de4SBram Moolenaar     static qfline_T *
get_next_valid_entry(qf_list_T * qfl,qfline_T * qf_ptr,int * qf_index,int dir)2664ef6b8de4SBram Moolenaar get_next_valid_entry(
2665fe15b7dfSBram Moolenaar 	qf_list_T	*qfl,
2666ef6b8de4SBram Moolenaar 	qfline_T	*qf_ptr,
2667ef6b8de4SBram Moolenaar 	int		*qf_index,
2668ef6b8de4SBram Moolenaar 	int		dir)
2669ef6b8de4SBram Moolenaar {
2670ef6b8de4SBram Moolenaar     int			idx;
2671ef6b8de4SBram Moolenaar     int			old_qf_fnum;
2672ef6b8de4SBram Moolenaar 
2673ef6b8de4SBram Moolenaar     idx = *qf_index;
2674ef6b8de4SBram Moolenaar     old_qf_fnum = qf_ptr->qf_fnum;
2675ef6b8de4SBram Moolenaar 
2676ef6b8de4SBram Moolenaar     do
2677ef6b8de4SBram Moolenaar     {
2678fe15b7dfSBram Moolenaar 	if (idx == qfl->qf_count || qf_ptr->qf_next == NULL)
2679ef6b8de4SBram Moolenaar 	    return NULL;
2680ef6b8de4SBram Moolenaar 	++idx;
2681ef6b8de4SBram Moolenaar 	qf_ptr = qf_ptr->qf_next;
2682fe15b7dfSBram Moolenaar     } while ((!qfl->qf_nonevalid && !qf_ptr->qf_valid)
2683ef6b8de4SBram Moolenaar 	    || (dir == FORWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum));
2684ef6b8de4SBram Moolenaar 
2685ef6b8de4SBram Moolenaar     *qf_index = idx;
2686ef6b8de4SBram Moolenaar     return qf_ptr;
2687ef6b8de4SBram Moolenaar }
2688ef6b8de4SBram Moolenaar 
2689ef6b8de4SBram Moolenaar /*
2690ef6b8de4SBram Moolenaar  * Get the previous valid entry in the current quickfix/location list. The
26919cb03716SBram Moolenaar  * search starts from the current entry.  Returns NULL on failure.
2692ef6b8de4SBram Moolenaar  */
2693ef6b8de4SBram Moolenaar     static qfline_T *
get_prev_valid_entry(qf_list_T * qfl,qfline_T * qf_ptr,int * qf_index,int dir)2694ef6b8de4SBram Moolenaar get_prev_valid_entry(
2695fe15b7dfSBram Moolenaar 	qf_list_T	*qfl,
2696ef6b8de4SBram Moolenaar 	qfline_T	*qf_ptr,
2697ef6b8de4SBram Moolenaar 	int		*qf_index,
2698ef6b8de4SBram Moolenaar 	int		dir)
2699ef6b8de4SBram Moolenaar {
2700ef6b8de4SBram Moolenaar     int			idx;
2701ef6b8de4SBram Moolenaar     int			old_qf_fnum;
2702ef6b8de4SBram Moolenaar 
2703ef6b8de4SBram Moolenaar     idx = *qf_index;
2704ef6b8de4SBram Moolenaar     old_qf_fnum = qf_ptr->qf_fnum;
2705ef6b8de4SBram Moolenaar 
2706ef6b8de4SBram Moolenaar     do
2707ef6b8de4SBram Moolenaar     {
2708ef6b8de4SBram Moolenaar 	if (idx == 1 || qf_ptr->qf_prev == NULL)
2709ef6b8de4SBram Moolenaar 	    return NULL;
2710ef6b8de4SBram Moolenaar 	--idx;
2711ef6b8de4SBram Moolenaar 	qf_ptr = qf_ptr->qf_prev;
2712fe15b7dfSBram Moolenaar     } while ((!qfl->qf_nonevalid && !qf_ptr->qf_valid)
2713ef6b8de4SBram Moolenaar 	    || (dir == BACKWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum));
2714ef6b8de4SBram Moolenaar 
2715ef6b8de4SBram Moolenaar     *qf_index = idx;
2716ef6b8de4SBram Moolenaar     return qf_ptr;
2717ef6b8de4SBram Moolenaar }
2718ef6b8de4SBram Moolenaar 
2719ef6b8de4SBram Moolenaar /*
2720ef6b8de4SBram Moolenaar  * Get the n'th (errornr) previous/next valid entry from the current entry in
2721ef6b8de4SBram Moolenaar  * the quickfix list.
2722ef6b8de4SBram Moolenaar  *   dir == FORWARD or FORWARD_FILE: next valid entry
2723ef6b8de4SBram Moolenaar  *   dir == BACKWARD or BACKWARD_FILE: previous valid entry
2724ef6b8de4SBram Moolenaar  */
2725ef6b8de4SBram Moolenaar     static qfline_T *
get_nth_valid_entry(qf_list_T * qfl,int errornr,int dir,int * new_qfidx)2726ef6b8de4SBram Moolenaar get_nth_valid_entry(
2727fe15b7dfSBram Moolenaar 	qf_list_T	*qfl,
2728ef6b8de4SBram Moolenaar 	int		errornr,
27296dae96efSBram Moolenaar 	int		dir,
27306dae96efSBram Moolenaar 	int		*new_qfidx)
2731ef6b8de4SBram Moolenaar {
27326dae96efSBram Moolenaar     qfline_T		*qf_ptr = qfl->qf_ptr;
27336dae96efSBram Moolenaar     int			qf_idx = qfl->qf_index;
2734ef6b8de4SBram Moolenaar     qfline_T		*prev_qf_ptr;
2735ef6b8de4SBram Moolenaar     int			prev_index;
2736ef6b8de4SBram Moolenaar     char_u		*err = e_no_more_items;
2737ef6b8de4SBram Moolenaar 
2738ef6b8de4SBram Moolenaar     while (errornr--)
2739ef6b8de4SBram Moolenaar     {
2740ef6b8de4SBram Moolenaar 	prev_qf_ptr = qf_ptr;
27416dae96efSBram Moolenaar 	prev_index = qf_idx;
2742ef6b8de4SBram Moolenaar 
2743ef6b8de4SBram Moolenaar 	if (dir == FORWARD || dir == FORWARD_FILE)
27446dae96efSBram Moolenaar 	    qf_ptr = get_next_valid_entry(qfl, qf_ptr, &qf_idx, dir);
2745ef6b8de4SBram Moolenaar 	else
27466dae96efSBram Moolenaar 	    qf_ptr = get_prev_valid_entry(qfl, qf_ptr, &qf_idx, dir);
2747ef6b8de4SBram Moolenaar 	if (qf_ptr == NULL)
2748ef6b8de4SBram Moolenaar 	{
2749ef6b8de4SBram Moolenaar 	    qf_ptr = prev_qf_ptr;
27506dae96efSBram Moolenaar 	    qf_idx = prev_index;
2751ef6b8de4SBram Moolenaar 	    if (err != NULL)
2752ef6b8de4SBram Moolenaar 	    {
2753f9e3e09fSBram Moolenaar 		emsg(_(err));
2754ef6b8de4SBram Moolenaar 		return NULL;
2755ef6b8de4SBram Moolenaar 	    }
2756ef6b8de4SBram Moolenaar 	    break;
2757ef6b8de4SBram Moolenaar 	}
2758ef6b8de4SBram Moolenaar 
2759ef6b8de4SBram Moolenaar 	err = NULL;
2760ef6b8de4SBram Moolenaar     }
2761ef6b8de4SBram Moolenaar 
27626dae96efSBram Moolenaar     *new_qfidx = qf_idx;
2763ef6b8de4SBram Moolenaar     return qf_ptr;
2764ef6b8de4SBram Moolenaar }
2765ef6b8de4SBram Moolenaar 
2766ef6b8de4SBram Moolenaar /*
27676dae96efSBram Moolenaar  * Get n'th (errornr) quickfix entry from the current entry in the quickfix
27686dae96efSBram Moolenaar  * list 'qfl'. Returns a pointer to the new entry and the index in 'new_qfidx'
2769ef6b8de4SBram Moolenaar  */
2770ef6b8de4SBram Moolenaar     static qfline_T *
get_nth_entry(qf_list_T * qfl,int errornr,int * new_qfidx)27716dae96efSBram Moolenaar get_nth_entry(qf_list_T *qfl, int errornr, int *new_qfidx)
2772ef6b8de4SBram Moolenaar {
27736dae96efSBram Moolenaar     qfline_T	*qf_ptr = qfl->qf_ptr;
27746dae96efSBram Moolenaar     int		qf_idx = qfl->qf_index;
2775ef6b8de4SBram Moolenaar 
27766dae96efSBram Moolenaar     // New error number is less than the current error number
2777ef6b8de4SBram Moolenaar     while (errornr < qf_idx && qf_idx > 1 && qf_ptr->qf_prev != NULL)
2778ef6b8de4SBram Moolenaar     {
2779ef6b8de4SBram Moolenaar 	--qf_idx;
2780ef6b8de4SBram Moolenaar 	qf_ptr = qf_ptr->qf_prev;
2781ef6b8de4SBram Moolenaar     }
27826dae96efSBram Moolenaar     // New error number is greater than the current error number
2783fe15b7dfSBram Moolenaar     while (errornr > qf_idx && qf_idx < qfl->qf_count &&
2784ef6b8de4SBram Moolenaar 						qf_ptr->qf_next != NULL)
2785ef6b8de4SBram Moolenaar     {
2786ef6b8de4SBram Moolenaar 	++qf_idx;
2787ef6b8de4SBram Moolenaar 	qf_ptr = qf_ptr->qf_next;
2788ef6b8de4SBram Moolenaar     }
2789ef6b8de4SBram Moolenaar 
27906dae96efSBram Moolenaar     *new_qfidx = qf_idx;
27916dae96efSBram Moolenaar     return qf_ptr;
27926dae96efSBram Moolenaar }
27936dae96efSBram Moolenaar 
27946dae96efSBram Moolenaar /*
27954b96df5aSBram Moolenaar  * Get a entry specified by 'errornr' and 'dir' from the current
27966dae96efSBram Moolenaar  * quickfix/location list. 'errornr' specifies the index of the entry and 'dir'
27976dae96efSBram Moolenaar  * specifies the direction (FORWARD/BACKWARD/FORWARD_FILE/BACKWARD_FILE).
27986dae96efSBram Moolenaar  * Returns a pointer to the entry and the index of the new entry is stored in
27996dae96efSBram Moolenaar  * 'new_qfidx'.
28006dae96efSBram Moolenaar  */
28016dae96efSBram Moolenaar     static qfline_T *
qf_get_entry(qf_list_T * qfl,int errornr,int dir,int * new_qfidx)28026dae96efSBram Moolenaar qf_get_entry(
28036dae96efSBram Moolenaar 	qf_list_T	*qfl,
28046dae96efSBram Moolenaar 	int		errornr,
28056dae96efSBram Moolenaar 	int		dir,
28066dae96efSBram Moolenaar 	int		*new_qfidx)
28076dae96efSBram Moolenaar {
28086dae96efSBram Moolenaar     qfline_T	*qf_ptr = qfl->qf_ptr;
28096dae96efSBram Moolenaar     int		qfidx = qfl->qf_index;
28106dae96efSBram Moolenaar 
28116dae96efSBram Moolenaar     if (dir != 0)    // next/prev valid entry
28126dae96efSBram Moolenaar 	qf_ptr = get_nth_valid_entry(qfl, errornr, dir, &qfidx);
28136dae96efSBram Moolenaar     else if (errornr != 0)	// go to specified number
28146dae96efSBram Moolenaar 	qf_ptr = get_nth_entry(qfl, errornr, &qfidx);
28156dae96efSBram Moolenaar 
28166dae96efSBram Moolenaar     *new_qfidx = qfidx;
2817ef6b8de4SBram Moolenaar     return qf_ptr;
2818ef6b8de4SBram Moolenaar }
2819ef6b8de4SBram Moolenaar 
2820ef6b8de4SBram Moolenaar /*
28217a2b0e55SBram Moolenaar  * Find a window displaying a Vim help file.
28227a2b0e55SBram Moolenaar  */
28237a2b0e55SBram Moolenaar     static win_T *
qf_find_help_win(void)28247a2b0e55SBram Moolenaar qf_find_help_win(void)
28257a2b0e55SBram Moolenaar {
28267a2b0e55SBram Moolenaar     win_T *wp;
28277a2b0e55SBram Moolenaar 
28287a2b0e55SBram Moolenaar     FOR_ALL_WINDOWS(wp)
28297a2b0e55SBram Moolenaar 	if (bt_help(wp->w_buffer))
28307a2b0e55SBram Moolenaar 	    return wp;
28317a2b0e55SBram Moolenaar 
28327a2b0e55SBram Moolenaar     return NULL;
28337a2b0e55SBram Moolenaar }
28347a2b0e55SBram Moolenaar 
28357a2b0e55SBram Moolenaar /*
28364aa47b28SBram Moolenaar  * Set the location list for the specified window to 'qi'.
28374aa47b28SBram Moolenaar  */
28384aa47b28SBram Moolenaar     static void
win_set_loclist(win_T * wp,qf_info_T * qi)28394aa47b28SBram Moolenaar win_set_loclist(win_T *wp, qf_info_T *qi)
28404aa47b28SBram Moolenaar {
28414aa47b28SBram Moolenaar     wp->w_llist = qi;
28424aa47b28SBram Moolenaar     qi->qf_refcount++;
28434aa47b28SBram Moolenaar }
28444aa47b28SBram Moolenaar 
28454aa47b28SBram Moolenaar /*
2846b244373bSBram Moolenaar  * Find a help window or open one. If 'newwin' is TRUE, then open a new help
2847b244373bSBram Moolenaar  * window.
2848ef6b8de4SBram Moolenaar  */
2849ef6b8de4SBram Moolenaar     static int
jump_to_help_window(qf_info_T * qi,int newwin,int * opened_window)2850b244373bSBram Moolenaar jump_to_help_window(qf_info_T *qi, int newwin, int *opened_window)
2851ef6b8de4SBram Moolenaar {
2852ef6b8de4SBram Moolenaar     win_T	*wp;
2853ef6b8de4SBram Moolenaar     int		flags;
2854ef6b8de4SBram Moolenaar 
2855e1004401SBram Moolenaar     if (cmdmod.cmod_tab != 0 || newwin)
2856ef6b8de4SBram Moolenaar 	wp = NULL;
2857ef6b8de4SBram Moolenaar     else
28587a2b0e55SBram Moolenaar 	wp = qf_find_help_win();
2859ef6b8de4SBram Moolenaar     if (wp != NULL && wp->w_buffer->b_nwindows > 0)
2860ef6b8de4SBram Moolenaar 	win_enter(wp, TRUE);
2861ef6b8de4SBram Moolenaar     else
2862ef6b8de4SBram Moolenaar     {
286300bf8cd2SBram Moolenaar 	// Split off help window; put it at far top if no position
286400bf8cd2SBram Moolenaar 	// specified, the current window is vertically split and narrow.
2865ef6b8de4SBram Moolenaar 	flags = WSP_HELP;
2866e1004401SBram Moolenaar 	if (cmdmod.cmod_split == 0 && curwin->w_width != Columns
2867ef6b8de4SBram Moolenaar 		&& curwin->w_width < 80)
2868ef6b8de4SBram Moolenaar 	    flags |= WSP_TOP;
2869b244373bSBram Moolenaar 	// If the user asks to open a new window, then copy the location list.
2870b244373bSBram Moolenaar 	// Otherwise, don't copy the location list.
2871b244373bSBram Moolenaar 	if (IS_LL_STACK(qi) && !newwin)
2872b244373bSBram Moolenaar 	    flags |= WSP_NEWLOC;
2873ef6b8de4SBram Moolenaar 
2874ef6b8de4SBram Moolenaar 	if (win_split(0, flags) == FAIL)
2875ef6b8de4SBram Moolenaar 	    return FAIL;
2876ef6b8de4SBram Moolenaar 
2877ef6b8de4SBram Moolenaar 	*opened_window = TRUE;
2878ef6b8de4SBram Moolenaar 
2879ef6b8de4SBram Moolenaar 	if (curwin->w_height < p_hh)
2880ef6b8de4SBram Moolenaar 	    win_setheight((int)p_hh);
2881ef6b8de4SBram Moolenaar 
2882b244373bSBram Moolenaar 	// When using location list, the new window should use the supplied
2883b244373bSBram Moolenaar 	// location list. If the user asks to open a new window, then the new
2884b244373bSBram Moolenaar 	// window will get a copy of the location list.
2885b244373bSBram Moolenaar 	if (IS_LL_STACK(qi) && !newwin)
28864aa47b28SBram Moolenaar 	    win_set_loclist(curwin, qi);
2887ef6b8de4SBram Moolenaar     }
2888ef6b8de4SBram Moolenaar 
2889ef6b8de4SBram Moolenaar     if (!p_im)
289000bf8cd2SBram Moolenaar 	restart_edit = 0;	    // don't want insert mode in help file
2891ef6b8de4SBram Moolenaar 
2892ef6b8de4SBram Moolenaar     return OK;
2893ef6b8de4SBram Moolenaar }
2894ef6b8de4SBram Moolenaar 
2895ef6b8de4SBram Moolenaar /*
2896ee8188fcSBram Moolenaar  * Find a non-quickfix window in the current tabpage using the given location
2897ee8188fcSBram Moolenaar  * list stack.
28987a2b0e55SBram Moolenaar  * Returns NULL if a matching window is not found.
2899071d4279SBram Moolenaar  */
29007a2b0e55SBram Moolenaar     static win_T *
qf_find_win_with_loclist(qf_info_T * ll)29017a2b0e55SBram Moolenaar qf_find_win_with_loclist(qf_info_T *ll)
2902071d4279SBram Moolenaar {
29037a2b0e55SBram Moolenaar     win_T	*wp;
2904071d4279SBram Moolenaar 
29057a2b0e55SBram Moolenaar     FOR_ALL_WINDOWS(wp)
29067a2b0e55SBram Moolenaar 	if (wp->w_llist == ll && !bt_quickfix(wp->w_buffer))
29077a2b0e55SBram Moolenaar 	    return wp;
290824862855SBram Moolenaar 
29097a2b0e55SBram Moolenaar     return NULL;
291024862855SBram Moolenaar }
2911d12f5c17SBram Moolenaar 
2912071d4279SBram Moolenaar /*
29137a2b0e55SBram Moolenaar  * Find a window containing a normal buffer
2914071d4279SBram Moolenaar  */
29157a2b0e55SBram Moolenaar     static win_T *
qf_find_win_with_normal_buf(void)29167a2b0e55SBram Moolenaar qf_find_win_with_normal_buf(void)
29177a2b0e55SBram Moolenaar {
29187a2b0e55SBram Moolenaar     win_T	*wp;
29197a2b0e55SBram Moolenaar 
29207a2b0e55SBram Moolenaar     FOR_ALL_WINDOWS(wp)
292191335e5aSBram Moolenaar 	if (bt_normal(wp->w_buffer))
29227a2b0e55SBram Moolenaar 	    return wp;
29237a2b0e55SBram Moolenaar 
29247a2b0e55SBram Moolenaar     return NULL;
29257a2b0e55SBram Moolenaar }
29267a2b0e55SBram Moolenaar 
29277a2b0e55SBram Moolenaar /*
29287a2b0e55SBram Moolenaar  * Go to a window in any tabpage containing the specified file.  Returns TRUE
29297a2b0e55SBram Moolenaar  * if successfully jumped to the window. Otherwise returns FALSE.
29307a2b0e55SBram Moolenaar  */
29317a2b0e55SBram Moolenaar     static int
qf_goto_tabwin_with_file(int fnum)29327a2b0e55SBram Moolenaar qf_goto_tabwin_with_file(int fnum)
293338c0a6e6SBram Moolenaar {
293438c0a6e6SBram Moolenaar     tabpage_T	*tp;
293538c0a6e6SBram Moolenaar     win_T	*wp;
293638c0a6e6SBram Moolenaar 
293738c0a6e6SBram Moolenaar     FOR_ALL_TAB_WINDOWS(tp, wp)
29387a2b0e55SBram Moolenaar 	if (wp->w_buffer->b_fnum == fnum)
293938c0a6e6SBram Moolenaar 	{
294038c0a6e6SBram Moolenaar 	    goto_tabpage_win(tp, wp);
29417a2b0e55SBram Moolenaar 	    return TRUE;
294238c0a6e6SBram Moolenaar 	}
29437a2b0e55SBram Moolenaar 
29447a2b0e55SBram Moolenaar     return FALSE;
294538c0a6e6SBram Moolenaar }
294638c0a6e6SBram Moolenaar 
294738c0a6e6SBram Moolenaar /*
29487a2b0e55SBram Moolenaar  * Create a new window to show a file above the quickfix window. Called when
29497a2b0e55SBram Moolenaar  * only the quickfix window is present.
295038c0a6e6SBram Moolenaar  */
29517a2b0e55SBram Moolenaar     static int
qf_open_new_file_win(qf_info_T * ll_ref)29527a2b0e55SBram Moolenaar qf_open_new_file_win(qf_info_T *ll_ref)
2953071d4279SBram Moolenaar {
29547a2b0e55SBram Moolenaar     int		flags;
29557a2b0e55SBram Moolenaar 
2956884ae644SBram Moolenaar     flags = WSP_ABOVE;
2957884ae644SBram Moolenaar     if (ll_ref != NULL)
2958884ae644SBram Moolenaar 	flags |= WSP_NEWLOC;
2959884ae644SBram Moolenaar     if (win_split(0, flags) == FAIL)
296000bf8cd2SBram Moolenaar 	return FAIL;		// not enough room for window
296100bf8cd2SBram Moolenaar     p_swb = empty_option;	// don't split again
2962446cb837SBram Moolenaar     swb_flags = 0;
29633368ea21SBram Moolenaar     RESET_BINDING(curwin);
2964d12f5c17SBram Moolenaar     if (ll_ref != NULL)
296500bf8cd2SBram Moolenaar 	// The new window should use the location list from the
296600bf8cd2SBram Moolenaar 	// location list window
29674aa47b28SBram Moolenaar 	win_set_loclist(curwin, ll_ref);
29687a2b0e55SBram Moolenaar     return OK;
2969071d4279SBram Moolenaar }
29707a2b0e55SBram Moolenaar 
29717a2b0e55SBram Moolenaar /*
29727a2b0e55SBram Moolenaar  * Go to a window that shows the right buffer. If the window is not found, go
29737a2b0e55SBram Moolenaar  * to the window just above the location list window. This is used for opening
29747a2b0e55SBram Moolenaar  * a file from a location window and not from a quickfix window. If some usable
29757a2b0e55SBram Moolenaar  * window is previously found, then it is supplied in 'use_win'.
29767a2b0e55SBram Moolenaar  */
29777a2b0e55SBram Moolenaar     static void
qf_goto_win_with_ll_file(win_T * use_win,int qf_fnum,qf_info_T * ll_ref)29787a2b0e55SBram Moolenaar qf_goto_win_with_ll_file(win_T *use_win, int qf_fnum, qf_info_T *ll_ref)
2979071d4279SBram Moolenaar {
29807a2b0e55SBram Moolenaar     win_T	*win = use_win;
29817a2b0e55SBram Moolenaar 
2982d12f5c17SBram Moolenaar     if (win == NULL)
2983d12f5c17SBram Moolenaar     {
298400bf8cd2SBram Moolenaar 	// Find the window showing the selected file
2985d12f5c17SBram Moolenaar 	FOR_ALL_WINDOWS(win)
29869cb03716SBram Moolenaar 	    if (win->w_buffer->b_fnum == qf_fnum)
2987d12f5c17SBram Moolenaar 		break;
2988d12f5c17SBram Moolenaar 	if (win == NULL)
2989d12f5c17SBram Moolenaar 	{
299000bf8cd2SBram Moolenaar 	    // Find a previous usable window
2991d12f5c17SBram Moolenaar 	    win = curwin;
2992d12f5c17SBram Moolenaar 	    do
2993d12f5c17SBram Moolenaar 	    {
299491335e5aSBram Moolenaar 		if (bt_normal(win->w_buffer))
2995d12f5c17SBram Moolenaar 		    break;
2996d12f5c17SBram Moolenaar 		if (win->w_prev == NULL)
299700bf8cd2SBram Moolenaar 		    win = lastwin;	// wrap around the top
2998d12f5c17SBram Moolenaar 		else
299900bf8cd2SBram Moolenaar 		    win = win->w_prev; // go to previous window
3000d12f5c17SBram Moolenaar 	    } while (win != curwin);
3001d12f5c17SBram Moolenaar 	}
3002d12f5c17SBram Moolenaar     }
3003d12f5c17SBram Moolenaar     win_goto(win);
3004d12f5c17SBram Moolenaar 
300500bf8cd2SBram Moolenaar     // If the location list for the window is not set, then set it
300600bf8cd2SBram Moolenaar     // to the location list from the location window
30070398e00aSBram Moolenaar     if (win->w_llist == NULL && ll_ref != NULL)
30084aa47b28SBram Moolenaar 	win_set_loclist(win, ll_ref);
3009d12f5c17SBram Moolenaar }
3010d12f5c17SBram Moolenaar 
3011071d4279SBram Moolenaar /*
3012fe15b7dfSBram Moolenaar  * Go to a window that contains the specified buffer 'qf_fnum'. If a window is
3013fe15b7dfSBram Moolenaar  * not found, then go to the window just above the quickfix window. This is
3014fe15b7dfSBram Moolenaar  * used for opening a file from a quickfix window and not from a location
3015fe15b7dfSBram Moolenaar  * window.
3016071d4279SBram Moolenaar  */
30177a2b0e55SBram Moolenaar     static void
qf_goto_win_with_qfl_file(int qf_fnum)30187a2b0e55SBram Moolenaar qf_goto_win_with_qfl_file(int qf_fnum)
30197a2b0e55SBram Moolenaar {
30207a2b0e55SBram Moolenaar     win_T	*win;
30217a2b0e55SBram Moolenaar     win_T	*altwin;
30227a2b0e55SBram Moolenaar 
3023071d4279SBram Moolenaar     win = curwin;
3024071d4279SBram Moolenaar     altwin = NULL;
3025071d4279SBram Moolenaar     for (;;)
3026071d4279SBram Moolenaar     {
30279cb03716SBram Moolenaar 	if (win->w_buffer->b_fnum == qf_fnum)
3028071d4279SBram Moolenaar 	    break;
3029071d4279SBram Moolenaar 	if (win->w_prev == NULL)
303000bf8cd2SBram Moolenaar 	    win = lastwin;	// wrap around the top
3031071d4279SBram Moolenaar 	else
303200bf8cd2SBram Moolenaar 	    win = win->w_prev;	// go to previous window
3033071d4279SBram Moolenaar 
3034d12f5c17SBram Moolenaar 	if (IS_QF_WINDOW(win))
3035071d4279SBram Moolenaar 	{
303600bf8cd2SBram Moolenaar 	    // Didn't find it, go to the window before the quickfix
3037539aa6b2SBram Moolenaar 	    // window, unless 'switchbuf' contains 'uselast': in this case we
3038539aa6b2SBram Moolenaar 	    // try to jump to the previously used window first.
3039539aa6b2SBram Moolenaar 	    if ((swb_flags & SWB_USELAST) && win_valid(prevwin))
3040539aa6b2SBram Moolenaar 		win = prevwin;
3041539aa6b2SBram Moolenaar 	    else if (altwin != NULL)
3042071d4279SBram Moolenaar 		win = altwin;
3043071d4279SBram Moolenaar 	    else if (curwin->w_prev != NULL)
3044071d4279SBram Moolenaar 		win = curwin->w_prev;
3045071d4279SBram Moolenaar 	    else
3046071d4279SBram Moolenaar 		win = curwin->w_next;
3047071d4279SBram Moolenaar 	    break;
3048071d4279SBram Moolenaar 	}
3049071d4279SBram Moolenaar 
305000bf8cd2SBram Moolenaar 	// Remember a usable window.
305191335e5aSBram Moolenaar 	if (altwin == NULL && !win->w_p_pvw && bt_normal(win->w_buffer))
3052071d4279SBram Moolenaar 	    altwin = win;
3053071d4279SBram Moolenaar     }
3054071d4279SBram Moolenaar 
3055071d4279SBram Moolenaar     win_goto(win);
3056071d4279SBram Moolenaar }
30577a2b0e55SBram Moolenaar 
30587a2b0e55SBram Moolenaar /*
30597a2b0e55SBram Moolenaar  * Find a suitable window for opening a file (qf_fnum) from the
30607a2b0e55SBram Moolenaar  * quickfix/location list and jump to it.  If the file is already opened in a
3061b244373bSBram Moolenaar  * window, jump to it. Otherwise open a new window to display the file. If
3062b244373bSBram Moolenaar  * 'newwin' is TRUE, then always open a new window. This is called from either
3063b244373bSBram Moolenaar  * a quickfix or a location list window.
30647a2b0e55SBram Moolenaar  */
30657a2b0e55SBram Moolenaar     static int
qf_jump_to_usable_window(int qf_fnum,int newwin,int * opened_window)3066b244373bSBram Moolenaar qf_jump_to_usable_window(int qf_fnum, int newwin, int *opened_window)
30677a2b0e55SBram Moolenaar {
3068f9ae154cSBram Moolenaar     win_T	*usable_wp = NULL;
3069f9ae154cSBram Moolenaar     int		usable_win = FALSE;
3070b244373bSBram Moolenaar     qf_info_T	*ll_ref = NULL;
30717a2b0e55SBram Moolenaar 
3072b244373bSBram Moolenaar     // If opening a new window, then don't use the location list referred by
3073b244373bSBram Moolenaar     // the current window.  Otherwise two windows will refer to the same
3074b244373bSBram Moolenaar     // location list.
3075b244373bSBram Moolenaar     if (!newwin)
30767a2b0e55SBram Moolenaar 	ll_ref = curwin->w_llist_ref;
3077b244373bSBram Moolenaar 
30787a2b0e55SBram Moolenaar     if (ll_ref != NULL)
30797a2b0e55SBram Moolenaar     {
308000bf8cd2SBram Moolenaar 	// Find a non-quickfix window with this location list
3081f9ae154cSBram Moolenaar 	usable_wp = qf_find_win_with_loclist(ll_ref);
3082f9ae154cSBram Moolenaar 	if (usable_wp != NULL)
3083f9ae154cSBram Moolenaar 	    usable_win = TRUE;
30847a2b0e55SBram Moolenaar     }
30857a2b0e55SBram Moolenaar 
30867a2b0e55SBram Moolenaar     if (!usable_win)
30877a2b0e55SBram Moolenaar     {
308800bf8cd2SBram Moolenaar 	// Locate a window showing a normal buffer
3089f9ae154cSBram Moolenaar 	win_T	*win = qf_find_win_with_normal_buf();
30907a2b0e55SBram Moolenaar 	if (win != NULL)
3091f9ae154cSBram Moolenaar 	    usable_win = TRUE;
30927a2b0e55SBram Moolenaar     }
30937a2b0e55SBram Moolenaar 
309400bf8cd2SBram Moolenaar     // If no usable window is found and 'switchbuf' contains "usetab"
309500bf8cd2SBram Moolenaar     // then search in other tabs.
30967a2b0e55SBram Moolenaar     if (!usable_win && (swb_flags & SWB_USETAB))
30977a2b0e55SBram Moolenaar 	usable_win = qf_goto_tabwin_with_file(qf_fnum);
30987a2b0e55SBram Moolenaar 
309900bf8cd2SBram Moolenaar     // If there is only one window and it is the quickfix window, create a
310000bf8cd2SBram Moolenaar     // new one above the quickfix window.
3101b244373bSBram Moolenaar     if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win || newwin)
31027a2b0e55SBram Moolenaar     {
31037a2b0e55SBram Moolenaar 	if (qf_open_new_file_win(ll_ref) != OK)
31047a2b0e55SBram Moolenaar 	    return FAIL;
310500bf8cd2SBram Moolenaar 	*opened_window = TRUE;	// close it when fail
31067a2b0e55SBram Moolenaar     }
31077a2b0e55SBram Moolenaar     else
31087a2b0e55SBram Moolenaar     {
310900bf8cd2SBram Moolenaar 	if (curwin->w_llist_ref != NULL)	// In a location window
3110f9ae154cSBram Moolenaar 	    qf_goto_win_with_ll_file(usable_wp, qf_fnum, ll_ref);
311100bf8cd2SBram Moolenaar 	else					// In a quickfix window
31127a2b0e55SBram Moolenaar 	    qf_goto_win_with_qfl_file(qf_fnum);
3113071d4279SBram Moolenaar     }
31149cb03716SBram Moolenaar 
31159cb03716SBram Moolenaar     return OK;
3116d12f5c17SBram Moolenaar }
3117071d4279SBram Moolenaar 
3118071d4279SBram Moolenaar /*
31199cb03716SBram Moolenaar  * Edit the selected file or help file.
31206dae96efSBram Moolenaar  * Returns OK if successfully edited the file, FAIL on failing to open the
31216dae96efSBram Moolenaar  * buffer and NOTDONE if the quickfix/location list was freed by an autocmd
31226dae96efSBram Moolenaar  * when opening the buffer.
3123071d4279SBram Moolenaar  */
31249cb03716SBram Moolenaar     static int
qf_jump_edit_buffer(qf_info_T * qi,qfline_T * qf_ptr,int forceit,int prev_winid,int * opened_window)31259cb03716SBram Moolenaar qf_jump_edit_buffer(
31269cb03716SBram Moolenaar 	qf_info_T	*qi,
31279cb03716SBram Moolenaar 	qfline_T	*qf_ptr,
31289cb03716SBram Moolenaar 	int		forceit,
3129eeb1b9c7SBram Moolenaar 	int		prev_winid,
31306dae96efSBram Moolenaar 	int		*opened_window)
313169a7cb47SBram Moolenaar {
31324aa47b28SBram Moolenaar     qf_list_T	*qfl = qf_get_curlist(qi);
31334d170af0SBram Moolenaar     int		old_changedtick = qfl->qf_changedtick;
31342d67d307SBram Moolenaar     qfltype_T	qfl_type = qfl->qfl_type;
31359cb03716SBram Moolenaar     int		retval = OK;
3136b6f1480aSBram Moolenaar     int		old_qf_curlist = qi->qf_curlist;
3137b6f1480aSBram Moolenaar     int		save_qfid = qfl->qf_id;
31389cb03716SBram Moolenaar 
313969a7cb47SBram Moolenaar     if (qf_ptr->qf_type == 1)
314069a7cb47SBram Moolenaar     {
314100bf8cd2SBram Moolenaar 	// Open help file (do_ecmd() will set b_help flag, readfile() will
314200bf8cd2SBram Moolenaar 	// set b_p_ro flag).
314369a7cb47SBram Moolenaar 	if (!can_abandon(curbuf, forceit))
314469a7cb47SBram Moolenaar 	{
3145f5be7cd0SBram Moolenaar 	    no_write_message();
3146b6f1480aSBram Moolenaar 	    return FAIL;
314769a7cb47SBram Moolenaar 	}
3148b6f1480aSBram Moolenaar 
31499cb03716SBram Moolenaar 	retval = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1,
3150701f7afcSBram Moolenaar 		ECMD_HIDE + ECMD_SET_HELP,
3151eeb1b9c7SBram Moolenaar 		prev_winid == curwin->w_id ? curwin : NULL);
315269a7cb47SBram Moolenaar     }
315369a7cb47SBram Moolenaar     else
31549cb03716SBram Moolenaar 	retval = buflist_getfile(qf_ptr->qf_fnum,
315569a7cb47SBram Moolenaar 		(linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit);
31563c097226SBram Moolenaar 
3157b6f1480aSBram Moolenaar     // If a location list, check whether the associated window is still
3158b6f1480aSBram Moolenaar     // present.
3159eeb1b9c7SBram Moolenaar     if (qfl_type == QFLT_LOCATION)
3160eeb1b9c7SBram Moolenaar     {
3161eeb1b9c7SBram Moolenaar 	win_T	*wp = win_id2wp(prev_winid);
3162eeb1b9c7SBram Moolenaar 	if (wp == NULL && curwin->w_llist != qi)
31630899d698SBram Moolenaar 	{
3164f9e3e09fSBram Moolenaar 	    emsg(_("E924: Current window was closed"));
31659cb03716SBram Moolenaar 	    *opened_window = FALSE;
31666dae96efSBram Moolenaar 	    return NOTDONE;
3167ffec3c53SBram Moolenaar 	}
3168eeb1b9c7SBram Moolenaar     }
3169b6f1480aSBram Moolenaar 
31702d67d307SBram Moolenaar     if (qfl_type == QFLT_QUICKFIX && !qflist_valid(NULL, save_qfid))
31713c097226SBram Moolenaar     {
31724d170af0SBram Moolenaar 	emsg(_(e_current_quickfix_list_was_changed));
31736dae96efSBram Moolenaar 	return NOTDONE;
31743c097226SBram Moolenaar     }
3175b6f1480aSBram Moolenaar 
31764d170af0SBram Moolenaar     // Check if the list was changed.  The pointers may happen to be identical,
31774d170af0SBram Moolenaar     // thus also check qf_changedtick.
3178b6f1480aSBram Moolenaar     if (old_qf_curlist != qi->qf_curlist
31794d170af0SBram Moolenaar 	    || old_changedtick != qfl->qf_changedtick
3180fe15b7dfSBram Moolenaar 	    || !is_qf_entry_present(qfl, qf_ptr))
3181ffec3c53SBram Moolenaar     {
31822d67d307SBram Moolenaar 	if (qfl_type == QFLT_QUICKFIX)
31834d170af0SBram Moolenaar 	    emsg(_(e_current_quickfix_list_was_changed));
3184ffec3c53SBram Moolenaar 	else
31854d170af0SBram Moolenaar 	    emsg(_(e_current_location_list_was_changed));
31866dae96efSBram Moolenaar 	return NOTDONE;
3187ffec3c53SBram Moolenaar     }
31889cb03716SBram Moolenaar 
31899cb03716SBram Moolenaar     return retval;
31909cb03716SBram Moolenaar }
31919cb03716SBram Moolenaar 
31929cb03716SBram Moolenaar /*
31937a2b0e55SBram Moolenaar  * Go to the error line in the current file using either line/column number or
31947a2b0e55SBram Moolenaar  * a search pattern.
31959cb03716SBram Moolenaar  */
31969cb03716SBram Moolenaar     static void
qf_jump_goto_line(linenr_T qf_lnum,int qf_col,char_u qf_viscol,char_u * qf_pattern)31979cb03716SBram Moolenaar qf_jump_goto_line(
31989cb03716SBram Moolenaar 	linenr_T	qf_lnum,
31999cb03716SBram Moolenaar 	int		qf_col,
32009cb03716SBram Moolenaar 	char_u		qf_viscol,
32019cb03716SBram Moolenaar 	char_u		*qf_pattern)
3202ffec3c53SBram Moolenaar {
32039cb03716SBram Moolenaar     linenr_T		i;
320469a7cb47SBram Moolenaar 
32059cb03716SBram Moolenaar     if (qf_pattern == NULL)
320668b76a69SBram Moolenaar     {
320700bf8cd2SBram Moolenaar 	// Go to line with error, unless qf_lnum is 0.
32089cb03716SBram Moolenaar 	i = qf_lnum;
3209071d4279SBram Moolenaar 	if (i > 0)
3210071d4279SBram Moolenaar 	{
3211071d4279SBram Moolenaar 	    if (i > curbuf->b_ml.ml_line_count)
3212071d4279SBram Moolenaar 		i = curbuf->b_ml.ml_line_count;
3213071d4279SBram Moolenaar 	    curwin->w_cursor.lnum = i;
3214071d4279SBram Moolenaar 	}
32159cb03716SBram Moolenaar 	if (qf_col > 0)
3216071d4279SBram Moolenaar 	{
3217b8c89003SBram Moolenaar 	    curwin->w_cursor.coladd = 0;
32189cb03716SBram Moolenaar 	    if (qf_viscol == TRUE)
3219c45eb770SBram Moolenaar 		coladvance(qf_col - 1);
3220071d4279SBram Moolenaar 	    else
3221c45eb770SBram Moolenaar 		curwin->w_cursor.col = qf_col - 1;
32222dfcef4cSBram Moolenaar 	    curwin->w_set_curswant = TRUE;
3223071d4279SBram Moolenaar 	    check_cursor();
3224071d4279SBram Moolenaar 	}
3225071d4279SBram Moolenaar 	else
3226071d4279SBram Moolenaar 	    beginline(BL_WHITE | BL_FIX);
322768b76a69SBram Moolenaar     }
322868b76a69SBram Moolenaar     else
322968b76a69SBram Moolenaar     {
323068b76a69SBram Moolenaar 	pos_T save_cursor;
323168b76a69SBram Moolenaar 
323200bf8cd2SBram Moolenaar 	// Move the cursor to the first line in the buffer
323368b76a69SBram Moolenaar 	save_cursor = curwin->w_cursor;
323468b76a69SBram Moolenaar 	curwin->w_cursor.lnum = 0;
3235c036e87bSBram Moolenaar 	if (!do_search(NULL, '/', '/', qf_pattern, (long)1, SEARCH_KEEP, NULL))
323668b76a69SBram Moolenaar 	    curwin->w_cursor = save_cursor;
323768b76a69SBram Moolenaar     }
32389cb03716SBram Moolenaar }
3239071d4279SBram Moolenaar 
32409cb03716SBram Moolenaar /*
32419cb03716SBram Moolenaar  * Display quickfix list index and size message
32429cb03716SBram Moolenaar  */
32439cb03716SBram Moolenaar     static void
qf_jump_print_msg(qf_info_T * qi,int qf_index,qfline_T * qf_ptr,buf_T * old_curbuf,linenr_T old_lnum)32449cb03716SBram Moolenaar qf_jump_print_msg(
32459cb03716SBram Moolenaar 	qf_info_T	*qi,
32469cb03716SBram Moolenaar 	int		qf_index,
32479cb03716SBram Moolenaar 	qfline_T	*qf_ptr,
32489cb03716SBram Moolenaar 	buf_T		*old_curbuf,
32499cb03716SBram Moolenaar 	linenr_T	old_lnum)
3250071d4279SBram Moolenaar {
32519cb03716SBram Moolenaar     linenr_T		i;
32529cb03716SBram Moolenaar     int			len;
32539cb03716SBram Moolenaar 
325400bf8cd2SBram Moolenaar     // Update the screen before showing the message, unless the screen
325500bf8cd2SBram Moolenaar     // scrolled up.
32568f55d103SBram Moolenaar     if (!msg_scrolled)
3257071d4279SBram Moolenaar 	update_topline_redraw();
3258071d4279SBram Moolenaar     sprintf((char *)IObuff, _("(%d of %d)%s%s: "), qf_index,
32594aa47b28SBram Moolenaar 	    qf_get_curlist(qi)->qf_count,
3260071d4279SBram Moolenaar 	    qf_ptr->qf_cleared ? _(" (line deleted)") : "",
3261071d4279SBram Moolenaar 	    (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
326200bf8cd2SBram Moolenaar     // Add the message, skipping leading whitespace and newlines.
3263071d4279SBram Moolenaar     len = (int)STRLEN(IObuff);
3264071d4279SBram Moolenaar     qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len);
3265071d4279SBram Moolenaar 
326600bf8cd2SBram Moolenaar     // Output the message.  Overwrite to avoid scrolling when the 'O'
326700bf8cd2SBram Moolenaar     // flag is present in 'shortmess'; But when not jumping, print the
326800bf8cd2SBram Moolenaar     // whole message.
3269071d4279SBram Moolenaar     i = msg_scroll;
3270071d4279SBram Moolenaar     if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum)
3271071d4279SBram Moolenaar 	msg_scroll = TRUE;
3272071d4279SBram Moolenaar     else if (!msg_scrolled && shortmess(SHM_OVERALL))
3273071d4279SBram Moolenaar 	msg_scroll = FALSE;
327432526b3cSBram Moolenaar     msg_attr_keep((char *)IObuff, 0, TRUE);
3275071d4279SBram Moolenaar     msg_scroll = i;
3276071d4279SBram Moolenaar }
32779cb03716SBram Moolenaar 
32789cb03716SBram Moolenaar /*
32796dae96efSBram Moolenaar  * Find a usable window for opening a file from the quickfix/location list. If
3280b244373bSBram Moolenaar  * a window is not found then open a new window. If 'newwin' is TRUE, then open
3281b244373bSBram Moolenaar  * a new window.
32826dae96efSBram Moolenaar  * Returns OK if successfully jumped or opened a window. Returns FAIL if not
32836dae96efSBram Moolenaar  * able to jump/open a window.  Returns NOTDONE if a file is not associated
32846dae96efSBram Moolenaar  * with the entry.
32856dae96efSBram Moolenaar  */
32866dae96efSBram Moolenaar     static int
qf_jump_open_window(qf_info_T * qi,qfline_T * qf_ptr,int newwin,int * opened_window)3287b244373bSBram Moolenaar qf_jump_open_window(
3288b244373bSBram Moolenaar 	qf_info_T	*qi,
3289b244373bSBram Moolenaar 	qfline_T	*qf_ptr,
3290b244373bSBram Moolenaar 	int		newwin,
3291b244373bSBram Moolenaar 	int		*opened_window)
32926dae96efSBram Moolenaar {
32934d170af0SBram Moolenaar     qf_list_T	*qfl = qf_get_curlist(qi);
32944d170af0SBram Moolenaar     int		old_changedtick = qfl->qf_changedtick;
32954d170af0SBram Moolenaar     int		old_qf_curlist = qi->qf_curlist;
32964d170af0SBram Moolenaar     qfltype_T	qfl_type = qfl->qfl_type;
32974d170af0SBram Moolenaar 
32986dae96efSBram Moolenaar     // For ":helpgrep" find a help window or open one.
3299e1004401SBram Moolenaar     if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer)
3300e1004401SBram Moolenaar 						      || cmdmod.cmod_tab != 0))
3301b244373bSBram Moolenaar 	if (jump_to_help_window(qi, newwin, opened_window) == FAIL)
33026dae96efSBram Moolenaar 	    return FAIL;
33034d170af0SBram Moolenaar     if (old_qf_curlist != qi->qf_curlist
33044d170af0SBram Moolenaar 	    || old_changedtick != qfl->qf_changedtick
33054d170af0SBram Moolenaar 	    || !is_qf_entry_present(qfl, qf_ptr))
33064d170af0SBram Moolenaar     {
33074d170af0SBram Moolenaar 	if (qfl_type == QFLT_QUICKFIX)
33084d170af0SBram Moolenaar 	    emsg(_(e_current_quickfix_list_was_changed));
33094d170af0SBram Moolenaar 	else
33104d170af0SBram Moolenaar 	    emsg(_(e_current_location_list_was_changed));
33114d170af0SBram Moolenaar 	return FAIL;
33124d170af0SBram Moolenaar     }
33136dae96efSBram Moolenaar 
33146dae96efSBram Moolenaar     // If currently in the quickfix window, find another window to show the
33156dae96efSBram Moolenaar     // file in.
33166dae96efSBram Moolenaar     if (bt_quickfix(curbuf) && !*opened_window)
33176dae96efSBram Moolenaar     {
33186dae96efSBram Moolenaar 	// If there is no file specified, we don't know where to go.
33196dae96efSBram Moolenaar 	// But do advance, otherwise ":cn" gets stuck.
33206dae96efSBram Moolenaar 	if (qf_ptr->qf_fnum == 0)
33216dae96efSBram Moolenaar 	    return NOTDONE;
33226dae96efSBram Moolenaar 
3323b244373bSBram Moolenaar 	if (qf_jump_to_usable_window(qf_ptr->qf_fnum, newwin,
3324b244373bSBram Moolenaar 						opened_window) == FAIL)
33256dae96efSBram Moolenaar 	    return FAIL;
33266dae96efSBram Moolenaar     }
33274d170af0SBram Moolenaar     if (old_qf_curlist != qi->qf_curlist
33284d170af0SBram Moolenaar 	    || old_changedtick != qfl->qf_changedtick
33294d170af0SBram Moolenaar 	    || !is_qf_entry_present(qfl, qf_ptr))
33304d170af0SBram Moolenaar     {
33314d170af0SBram Moolenaar 	if (qfl_type == QFLT_QUICKFIX)
33324d170af0SBram Moolenaar 	    emsg(_(e_current_quickfix_list_was_changed));
33334d170af0SBram Moolenaar 	else
33344d170af0SBram Moolenaar 	    emsg(_(e_current_location_list_was_changed));
33354d170af0SBram Moolenaar 	return FAIL;
33364d170af0SBram Moolenaar     }
33376dae96efSBram Moolenaar 
33386dae96efSBram Moolenaar     return OK;
33396dae96efSBram Moolenaar }
33406dae96efSBram Moolenaar 
33416dae96efSBram Moolenaar /*
33426dae96efSBram Moolenaar  * Edit a selected file from the quickfix/location list and jump to a
33436dae96efSBram Moolenaar  * particular line/column, adjust the folds and display a message about the
33446dae96efSBram Moolenaar  * jump.
33456dae96efSBram Moolenaar  * Returns OK on success and FAIL on failing to open the file/buffer.  Returns
33466dae96efSBram Moolenaar  * NOTDONE if the quickfix/location list is freed by an autocmd when opening
33476dae96efSBram Moolenaar  * the file.
33486dae96efSBram Moolenaar  */
33496dae96efSBram Moolenaar     static int
qf_jump_to_buffer(qf_info_T * qi,int qf_index,qfline_T * qf_ptr,int forceit,int prev_winid,int * opened_window,int openfold,int print_message)33506dae96efSBram Moolenaar qf_jump_to_buffer(
33516dae96efSBram Moolenaar 	qf_info_T	*qi,
33526dae96efSBram Moolenaar 	int		qf_index,
33536dae96efSBram Moolenaar 	qfline_T	*qf_ptr,
33546dae96efSBram Moolenaar 	int		forceit,
3355eeb1b9c7SBram Moolenaar 	int		prev_winid,
33566dae96efSBram Moolenaar 	int		*opened_window,
33576dae96efSBram Moolenaar 	int		openfold,
33586dae96efSBram Moolenaar 	int		print_message)
33596dae96efSBram Moolenaar {
33606dae96efSBram Moolenaar     buf_T	*old_curbuf;
33616dae96efSBram Moolenaar     linenr_T	old_lnum;
33626dae96efSBram Moolenaar     int		retval = OK;
33636dae96efSBram Moolenaar 
33646dae96efSBram Moolenaar     // If there is a file name, read the wanted file if needed, and check
33656dae96efSBram Moolenaar     // autowrite etc.
33666dae96efSBram Moolenaar     old_curbuf = curbuf;
33676dae96efSBram Moolenaar     old_lnum = curwin->w_cursor.lnum;
33686dae96efSBram Moolenaar 
33696dae96efSBram Moolenaar     if (qf_ptr->qf_fnum != 0)
33706dae96efSBram Moolenaar     {
3371eeb1b9c7SBram Moolenaar 	retval = qf_jump_edit_buffer(qi, qf_ptr, forceit, prev_winid,
33726dae96efSBram Moolenaar 						opened_window);
33736dae96efSBram Moolenaar 	if (retval != OK)
33746dae96efSBram Moolenaar 	    return retval;
33756dae96efSBram Moolenaar     }
33766dae96efSBram Moolenaar 
33776dae96efSBram Moolenaar     // When not switched to another buffer, still need to set pc mark
33786dae96efSBram Moolenaar     if (curbuf == old_curbuf)
33796dae96efSBram Moolenaar 	setpcmark();
33806dae96efSBram Moolenaar 
33816dae96efSBram Moolenaar     qf_jump_goto_line(qf_ptr->qf_lnum, qf_ptr->qf_col, qf_ptr->qf_viscol,
33826dae96efSBram Moolenaar 	    qf_ptr->qf_pattern);
33836dae96efSBram Moolenaar 
33846dae96efSBram Moolenaar #ifdef FEAT_FOLDING
33856dae96efSBram Moolenaar     if ((fdo_flags & FDO_QUICKFIX) && openfold)
33866dae96efSBram Moolenaar 	foldOpenCursor();
33876dae96efSBram Moolenaar #endif
33886dae96efSBram Moolenaar     if (print_message)
33896dae96efSBram Moolenaar 	qf_jump_print_msg(qi, qf_index, qf_ptr, old_curbuf, old_lnum);
33906dae96efSBram Moolenaar 
33916dae96efSBram Moolenaar     return retval;
33926dae96efSBram Moolenaar }
33936dae96efSBram Moolenaar 
33946dae96efSBram Moolenaar /*
33955b69c22fSBram Moolenaar  * Jump to a quickfix line and try to use an existing window.
33969cb03716SBram Moolenaar  */
33979cb03716SBram Moolenaar     void
qf_jump(qf_info_T * qi,int dir,int errornr,int forceit)33989cb03716SBram Moolenaar qf_jump(qf_info_T	*qi,
33999cb03716SBram Moolenaar 	int		dir,
34009cb03716SBram Moolenaar 	int		errornr,
34019cb03716SBram Moolenaar 	int		forceit)
34029cb03716SBram Moolenaar {
3403b244373bSBram Moolenaar     qf_jump_newwin(qi, dir, errornr, forceit, FALSE);
3404b244373bSBram Moolenaar }
3405b244373bSBram Moolenaar 
3406b244373bSBram Moolenaar /*
34075b69c22fSBram Moolenaar  * Jump to a quickfix line.
34085b69c22fSBram Moolenaar  * If dir == 0 go to entry "errornr".
34095b69c22fSBram Moolenaar  * If dir == FORWARD go "errornr" valid entries forward.
34105b69c22fSBram Moolenaar  * If dir == BACKWARD go "errornr" valid entries backward.
34115b69c22fSBram Moolenaar  * If dir == FORWARD_FILE go "errornr" valid entries files backward.
34125b69c22fSBram Moolenaar  * If dir == BACKWARD_FILE go "errornr" valid entries files backward
34135b69c22fSBram Moolenaar  * else if "errornr" is zero, redisplay the same line
34145b69c22fSBram Moolenaar  * If 'forceit' is TRUE, then can discard changes to the current buffer.
3415b244373bSBram Moolenaar  * If 'newwin' is TRUE, then open the file in a new window.
3416b244373bSBram Moolenaar  */
34175843f5f3SBram Moolenaar     static void
qf_jump_newwin(qf_info_T * qi,int dir,int errornr,int forceit,int newwin)3418b244373bSBram Moolenaar qf_jump_newwin(qf_info_T	*qi,
3419b244373bSBram Moolenaar 	int		dir,
3420b244373bSBram Moolenaar 	int		errornr,
3421b244373bSBram Moolenaar 	int		forceit,
3422b244373bSBram Moolenaar 	int		newwin)
3423b244373bSBram Moolenaar {
3424fe15b7dfSBram Moolenaar     qf_list_T		*qfl;
34259cb03716SBram Moolenaar     qfline_T		*qf_ptr;
34269cb03716SBram Moolenaar     qfline_T		*old_qf_ptr;
34279cb03716SBram Moolenaar     int			qf_index;
34289cb03716SBram Moolenaar     int			old_qf_index;
34299cb03716SBram Moolenaar     char_u		*old_swb = p_swb;
34309cb03716SBram Moolenaar     unsigned		old_swb_flags = swb_flags;
3431eeb1b9c7SBram Moolenaar     int			prev_winid;
34329cb03716SBram Moolenaar     int			opened_window = FALSE;
34339cb03716SBram Moolenaar     int			print_message = TRUE;
34346dae96efSBram Moolenaar     int			old_KeyTyped = KeyTyped; // getting file may reset it
34359cb03716SBram Moolenaar     int			retval = OK;
34369cb03716SBram Moolenaar 
34379cb03716SBram Moolenaar     if (qi == NULL)
34389cb03716SBram Moolenaar 	qi = &ql_info;
34399cb03716SBram Moolenaar 
34400398e00aSBram Moolenaar     if (qf_stack_empty(qi) || qf_list_empty(qf_get_curlist(qi)))
34419cb03716SBram Moolenaar     {
3442e29a27f6SBram Moolenaar 	emsg(_(e_no_errors));
34439cb03716SBram Moolenaar 	return;
34449cb03716SBram Moolenaar     }
34459cb03716SBram Moolenaar 
3446eeb1b9c7SBram Moolenaar     incr_quickfix_busy();
3447eeb1b9c7SBram Moolenaar 
34484aa47b28SBram Moolenaar     qfl = qf_get_curlist(qi);
3449fe15b7dfSBram Moolenaar 
3450fe15b7dfSBram Moolenaar     qf_ptr = qfl->qf_ptr;
34519cb03716SBram Moolenaar     old_qf_ptr = qf_ptr;
3452fe15b7dfSBram Moolenaar     qf_index = qfl->qf_index;
34539cb03716SBram Moolenaar     old_qf_index = qf_index;
34546dae96efSBram Moolenaar 
34556dae96efSBram Moolenaar     qf_ptr = qf_get_entry(qfl, errornr, dir, &qf_index);
34569cb03716SBram Moolenaar     if (qf_ptr == NULL)
34579cb03716SBram Moolenaar     {
34589cb03716SBram Moolenaar 	qf_ptr = old_qf_ptr;
34599cb03716SBram Moolenaar 	qf_index = old_qf_index;
34609cb03716SBram Moolenaar 	goto theend;
34619cb03716SBram Moolenaar     }
34629cb03716SBram Moolenaar 
3463fe15b7dfSBram Moolenaar     qfl->qf_index = qf_index;
34641557b16dSWei-Chung Wen     qfl->qf_ptr = qf_ptr;
34659cb03716SBram Moolenaar     if (qf_win_pos_update(qi, old_qf_index))
34666dae96efSBram Moolenaar 	// No need to print the error message if it's visible in the error
34676dae96efSBram Moolenaar 	// window
34689cb03716SBram Moolenaar 	print_message = FALSE;
34699cb03716SBram Moolenaar 
3470eeb1b9c7SBram Moolenaar     prev_winid = curwin->w_id;
3471eeb1b9c7SBram Moolenaar 
3472b244373bSBram Moolenaar     retval = qf_jump_open_window(qi, qf_ptr, newwin, &opened_window);
34736dae96efSBram Moolenaar     if (retval == FAIL)
34749cb03716SBram Moolenaar 	goto failed;
34756dae96efSBram Moolenaar     if (retval == NOTDONE)
34766dae96efSBram Moolenaar 	goto theend;
34779cb03716SBram Moolenaar 
3478eeb1b9c7SBram Moolenaar     retval = qf_jump_to_buffer(qi, qf_index, qf_ptr, forceit, prev_winid,
34796dae96efSBram Moolenaar 				  &opened_window, old_KeyTyped, print_message);
34806dae96efSBram Moolenaar     if (retval == NOTDONE)
34819cb03716SBram Moolenaar     {
34826dae96efSBram Moolenaar 	// Quickfix/location list is freed by an autocmd
34839cb03716SBram Moolenaar 	qi = NULL;
34849cb03716SBram Moolenaar 	qf_ptr = NULL;
34859cb03716SBram Moolenaar     }
34869cb03716SBram Moolenaar 
34876dae96efSBram Moolenaar     if (retval != OK)
3488071d4279SBram Moolenaar     {
3489071d4279SBram Moolenaar 	if (opened_window)
34906dae96efSBram Moolenaar 	    win_close(curwin, TRUE);    // Close opened window
34910899d698SBram Moolenaar 	if (qf_ptr != NULL && qf_ptr->qf_fnum != 0)
3492071d4279SBram Moolenaar 	{
34936dae96efSBram Moolenaar 	    // Couldn't open file, so put index back where it was.  This could
34946dae96efSBram Moolenaar 	    // happen if the file was readonly and we changed something.
3495071d4279SBram Moolenaar failed:
3496071d4279SBram Moolenaar 	    qf_ptr = old_qf_ptr;
3497071d4279SBram Moolenaar 	    qf_index = old_qf_index;
3498071d4279SBram Moolenaar 	}
3499071d4279SBram Moolenaar     }
3500071d4279SBram Moolenaar theend:
35010899d698SBram Moolenaar     if (qi != NULL)
35020899d698SBram Moolenaar     {
3503fe15b7dfSBram Moolenaar 	qfl->qf_ptr = qf_ptr;
3504fe15b7dfSBram Moolenaar 	qfl->qf_index = qf_index;
35050899d698SBram Moolenaar     }
3506f9ae154cSBram Moolenaar     if (p_swb != old_swb && p_swb == empty_option)
3507071d4279SBram Moolenaar     {
35086dae96efSBram Moolenaar 	// Restore old 'switchbuf' value, but not when an autocommand or
35096dae96efSBram Moolenaar 	// modeline has changed the value.
3510071d4279SBram Moolenaar 	p_swb = old_swb;
3511446cb837SBram Moolenaar 	swb_flags = old_swb_flags;
3512446cb837SBram Moolenaar     }
3513eeb1b9c7SBram Moolenaar     decr_quickfix_busy();
3514071d4279SBram Moolenaar }
3515071d4279SBram Moolenaar 
351600bf8cd2SBram Moolenaar // Highlight attributes used for displaying entries from the quickfix list.
3517de3b3677SBram Moolenaar static int	qfFileAttr;
3518de3b3677SBram Moolenaar static int	qfSepAttr;
3519de3b3677SBram Moolenaar static int	qfLineAttr;
3520de3b3677SBram Moolenaar 
3521de3b3677SBram Moolenaar /*
3522de3b3677SBram Moolenaar  * Display information about a single entry from the quickfix/location list.
3523de3b3677SBram Moolenaar  * Used by ":clist/:llist" commands.
3524fe15b7dfSBram Moolenaar  * 'cursel' will be set to TRUE for the currently selected entry in the
3525fe15b7dfSBram Moolenaar  * quickfix list.
3526de3b3677SBram Moolenaar  */
3527de3b3677SBram Moolenaar     static void
qf_list_entry(qfline_T * qfp,int qf_idx,int cursel)3528fe15b7dfSBram Moolenaar qf_list_entry(qfline_T *qfp, int qf_idx, int cursel)
3529de3b3677SBram Moolenaar {
3530de3b3677SBram Moolenaar     char_u	*fname;
3531de3b3677SBram Moolenaar     buf_T	*buf;
3532de3b3677SBram Moolenaar     int		filter_entry;
3533de3b3677SBram Moolenaar 
3534de3b3677SBram Moolenaar     fname = NULL;
3535de3b3677SBram Moolenaar     if (qfp->qf_module != NULL && *qfp->qf_module != NUL)
3536de3b3677SBram Moolenaar 	vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx,
3537de3b3677SBram Moolenaar 						(char *)qfp->qf_module);
3538de3b3677SBram Moolenaar     else {
3539de3b3677SBram Moolenaar 	if (qfp->qf_fnum != 0
3540de3b3677SBram Moolenaar 		&& (buf = buflist_findnr(qfp->qf_fnum)) != NULL)
3541de3b3677SBram Moolenaar 	{
3542de3b3677SBram Moolenaar 	    fname = buf->b_fname;
354300bf8cd2SBram Moolenaar 	    if (qfp->qf_type == 1)	// :helpgrep
3544de3b3677SBram Moolenaar 		fname = gettail(fname);
3545de3b3677SBram Moolenaar 	}
3546de3b3677SBram Moolenaar 	if (fname == NULL)
3547de3b3677SBram Moolenaar 	    sprintf((char *)IObuff, "%2d", qf_idx);
3548de3b3677SBram Moolenaar 	else
3549de3b3677SBram Moolenaar 	    vim_snprintf((char *)IObuff, IOSIZE, "%2d %s",
3550de3b3677SBram Moolenaar 		    qf_idx, (char *)fname);
3551de3b3677SBram Moolenaar     }
3552de3b3677SBram Moolenaar 
3553de3b3677SBram Moolenaar     // Support for filtering entries using :filter /pat/ clist
3554de3b3677SBram Moolenaar     // Match against the module name, file name, search pattern and
3555de3b3677SBram Moolenaar     // text of the entry.
3556de3b3677SBram Moolenaar     filter_entry = TRUE;
3557de3b3677SBram Moolenaar     if (qfp->qf_module != NULL && *qfp->qf_module != NUL)
3558de3b3677SBram Moolenaar 	filter_entry &= message_filtered(qfp->qf_module);
3559de3b3677SBram Moolenaar     if (filter_entry && fname != NULL)
3560de3b3677SBram Moolenaar 	filter_entry &= message_filtered(fname);
3561de3b3677SBram Moolenaar     if (filter_entry && qfp->qf_pattern != NULL)
3562de3b3677SBram Moolenaar 	filter_entry &= message_filtered(qfp->qf_pattern);
3563de3b3677SBram Moolenaar     if (filter_entry)
3564de3b3677SBram Moolenaar 	filter_entry &= message_filtered(qfp->qf_text);
3565de3b3677SBram Moolenaar     if (filter_entry)
3566de3b3677SBram Moolenaar 	return;
3567de3b3677SBram Moolenaar 
3568de3b3677SBram Moolenaar     msg_putchar('\n');
3569fe15b7dfSBram Moolenaar     msg_outtrans_attr(IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr);
3570de3b3677SBram Moolenaar 
3571de3b3677SBram Moolenaar     if (qfp->qf_lnum != 0)
357232526b3cSBram Moolenaar 	msg_puts_attr(":", qfSepAttr);
3573de3b3677SBram Moolenaar     if (qfp->qf_lnum == 0)
3574de3b3677SBram Moolenaar 	IObuff[0] = NUL;
3575de3b3677SBram Moolenaar     else
35766864efa5Sthinca 	qf_range_text(qfp, IObuff, IOSIZE);
3577de3b3677SBram Moolenaar     sprintf((char *)IObuff + STRLEN(IObuff), "%s",
3578de3b3677SBram Moolenaar 	    (char *)qf_types(qfp->qf_type, qfp->qf_nr));
357932526b3cSBram Moolenaar     msg_puts_attr((char *)IObuff, qfLineAttr);
358032526b3cSBram Moolenaar     msg_puts_attr(":", qfSepAttr);
3581de3b3677SBram Moolenaar     if (qfp->qf_pattern != NULL)
3582de3b3677SBram Moolenaar     {
3583de3b3677SBram Moolenaar 	qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE);
358432526b3cSBram Moolenaar 	msg_puts((char *)IObuff);
358532526b3cSBram Moolenaar 	msg_puts_attr(":", qfSepAttr);
3586de3b3677SBram Moolenaar     }
358732526b3cSBram Moolenaar     msg_puts(" ");
3588de3b3677SBram Moolenaar 
358900bf8cd2SBram Moolenaar     // Remove newlines and leading whitespace from the text.  For an
359000bf8cd2SBram Moolenaar     // unrecognized line keep the indent, the compiler may mark a word
359100bf8cd2SBram Moolenaar     // with ^^^^.
3592de3b3677SBram Moolenaar     qf_fmt_text((fname != NULL || qfp->qf_lnum != 0)
3593de3b3677SBram Moolenaar 				? skipwhite(qfp->qf_text) : qfp->qf_text,
3594de3b3677SBram Moolenaar 				IObuff, IOSIZE);
3595de3b3677SBram Moolenaar     msg_prt_line(IObuff, FALSE);
359600bf8cd2SBram Moolenaar     out_flush();		// show one line at a time
3597de3b3677SBram Moolenaar }
3598de3b3677SBram Moolenaar 
3599de3b3677SBram Moolenaar /*
3600071d4279SBram Moolenaar  * ":clist": list all errors
3601d12f5c17SBram Moolenaar  * ":llist": list all locations
3602071d4279SBram Moolenaar  */
3603071d4279SBram Moolenaar     void
qf_list(exarg_T * eap)360405540976SBram Moolenaar qf_list(exarg_T *eap)
3605071d4279SBram Moolenaar {
3606fe15b7dfSBram Moolenaar     qf_list_T	*qfl;
360768b76a69SBram Moolenaar     qfline_T	*qfp;
3608071d4279SBram Moolenaar     int		i;
3609071d4279SBram Moolenaar     int		idx1 = 1;
3610071d4279SBram Moolenaar     int		idx2 = -1;
3611071d4279SBram Moolenaar     char_u	*arg = eap->arg;
3612e8fea072SBram Moolenaar     int		plus = FALSE;
361300bf8cd2SBram Moolenaar     int		all = eap->forceit;	// if not :cl!, only show
361400bf8cd2SBram Moolenaar 					// recognised errors
361587f59b09SBram Moolenaar     qf_info_T	*qi;
3616071d4279SBram Moolenaar 
361787f59b09SBram Moolenaar     if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
3618d12f5c17SBram Moolenaar 	return;
3619d12f5c17SBram Moolenaar 
36200398e00aSBram Moolenaar     if (qf_stack_empty(qi) || qf_list_empty(qf_get_curlist(qi)))
3621071d4279SBram Moolenaar     {
3622e29a27f6SBram Moolenaar 	emsg(_(e_no_errors));
3623071d4279SBram Moolenaar 	return;
3624071d4279SBram Moolenaar     }
3625e8fea072SBram Moolenaar     if (*arg == '+')
3626e8fea072SBram Moolenaar     {
3627e8fea072SBram Moolenaar 	++arg;
3628e8fea072SBram Moolenaar 	plus = TRUE;
3629e8fea072SBram Moolenaar     }
3630071d4279SBram Moolenaar     if (!get_list_range(&arg, &idx1, &idx2) || *arg != NUL)
3631071d4279SBram Moolenaar     {
36322d06bfdeSBram Moolenaar 	semsg(_(e_trailing_arg), arg);
3633071d4279SBram Moolenaar 	return;
3634071d4279SBram Moolenaar     }
36354aa47b28SBram Moolenaar     qfl = qf_get_curlist(qi);
3636e8fea072SBram Moolenaar     if (plus)
3637e8fea072SBram Moolenaar     {
3638fe15b7dfSBram Moolenaar 	i = qfl->qf_index;
3639e8fea072SBram Moolenaar 	idx2 = i + idx1;
3640e8fea072SBram Moolenaar 	idx1 = i;
3641e8fea072SBram Moolenaar     }
3642e8fea072SBram Moolenaar     else
3643e8fea072SBram Moolenaar     {
3644fe15b7dfSBram Moolenaar 	i = qfl->qf_count;
3645071d4279SBram Moolenaar 	if (idx1 < 0)
3646071d4279SBram Moolenaar 	    idx1 = (-idx1 > i) ? 0 : idx1 + i + 1;
3647071d4279SBram Moolenaar 	if (idx2 < 0)
3648071d4279SBram Moolenaar 	    idx2 = (-idx2 > i) ? 0 : idx2 + i + 1;
3649e8fea072SBram Moolenaar     }
3650071d4279SBram Moolenaar 
365100bf8cd2SBram Moolenaar     // Shorten all the file names, so that it is easy to read
3652a796d46fSBram Moolenaar     shorten_fnames(FALSE);
3653a796d46fSBram Moolenaar 
365400bf8cd2SBram Moolenaar     // Get the attributes for the different quickfix highlight items.  Note
365500bf8cd2SBram Moolenaar     // that this depends on syntax items defined in the qf.vim syntax file
365693a32e2eSBram Moolenaar     qfFileAttr = syn_name2attr((char_u *)"qfFileName");
365793a32e2eSBram Moolenaar     if (qfFileAttr == 0)
365893a32e2eSBram Moolenaar 	qfFileAttr = HL_ATTR(HLF_D);
365993a32e2eSBram Moolenaar     qfSepAttr = syn_name2attr((char_u *)"qfSeparator");
366093a32e2eSBram Moolenaar     if (qfSepAttr == 0)
366193a32e2eSBram Moolenaar 	qfSepAttr = HL_ATTR(HLF_D);
366293a32e2eSBram Moolenaar     qfLineAttr = syn_name2attr((char_u *)"qfLineNr");
366393a32e2eSBram Moolenaar     if (qfLineAttr == 0)
366493a32e2eSBram Moolenaar 	qfLineAttr = HL_ATTR(HLF_N);
366593a32e2eSBram Moolenaar 
3666fe15b7dfSBram Moolenaar     if (qfl->qf_nonevalid)
3667071d4279SBram Moolenaar 	all = TRUE;
366895946f12SBram Moolenaar     FOR_ALL_QFL_ITEMS(qfl, qfp, i)
3669071d4279SBram Moolenaar     {
3670071d4279SBram Moolenaar 	if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2)
3671fe15b7dfSBram Moolenaar 	    qf_list_entry(qfp, i, i == qfl->qf_index);
36724cde86c2SBram Moolenaar 
3673071d4279SBram Moolenaar 	ui_breakcheck();
3674071d4279SBram Moolenaar     }
3675071d4279SBram Moolenaar }
3676071d4279SBram Moolenaar 
3677071d4279SBram Moolenaar /*
3678071d4279SBram Moolenaar  * Remove newlines and leading whitespace from an error message.
3679071d4279SBram Moolenaar  * Put the result in "buf[bufsize]".
3680071d4279SBram Moolenaar  */
3681071d4279SBram Moolenaar     static void
qf_fmt_text(char_u * text,char_u * buf,int bufsize)368205540976SBram Moolenaar qf_fmt_text(char_u *text, char_u *buf, int bufsize)
3683071d4279SBram Moolenaar {
3684071d4279SBram Moolenaar     int		i;
3685071d4279SBram Moolenaar     char_u	*p = text;
3686071d4279SBram Moolenaar 
3687071d4279SBram Moolenaar     for (i = 0; *p != NUL && i < bufsize - 1; ++i)
3688071d4279SBram Moolenaar     {
3689071d4279SBram Moolenaar 	if (*p == '\n')
3690071d4279SBram Moolenaar 	{
3691071d4279SBram Moolenaar 	    buf[i] = ' ';
3692071d4279SBram Moolenaar 	    while (*++p != NUL)
36931c465444SBram Moolenaar 		if (!VIM_ISWHITE(*p) && *p != '\n')
3694071d4279SBram Moolenaar 		    break;
3695071d4279SBram Moolenaar 	}
3696071d4279SBram Moolenaar 	else
3697071d4279SBram Moolenaar 	    buf[i] = *p++;
3698071d4279SBram Moolenaar     }
3699071d4279SBram Moolenaar     buf[i] = NUL;
3700071d4279SBram Moolenaar }
3701071d4279SBram Moolenaar 
370218cebf44SBram Moolenaar /*
37036864efa5Sthinca  * Range information from lnum, col, end_lnum, and end_col.
37046864efa5Sthinca  * Put the result in "buf[bufsize]".
37056864efa5Sthinca  */
37066864efa5Sthinca     static void
qf_range_text(qfline_T * qfp,char_u * buf,int bufsize)37076864efa5Sthinca qf_range_text(qfline_T *qfp, char_u *buf, int bufsize)
37086864efa5Sthinca {
37096864efa5Sthinca     int len;
37106864efa5Sthinca     vim_snprintf((char *)buf, bufsize, "%ld", qfp->qf_lnum);
37116864efa5Sthinca     len = (int)STRLEN(buf);
37126864efa5Sthinca 
37136864efa5Sthinca     if (qfp->qf_end_lnum > 0 && qfp->qf_lnum != qfp->qf_end_lnum)
37146864efa5Sthinca     {
37156864efa5Sthinca 	vim_snprintf((char *)buf + len, bufsize - len,
37166864efa5Sthinca 		"-%ld", qfp->qf_end_lnum);
37176864efa5Sthinca 	len += (int)STRLEN(buf + len);
37186864efa5Sthinca     }
37196864efa5Sthinca     if (qfp->qf_col > 0)
37206864efa5Sthinca     {
37216864efa5Sthinca 	vim_snprintf((char *)buf + len, bufsize - len, " col %d", qfp->qf_col);
37226864efa5Sthinca 	len += (int)STRLEN(buf + len);
37236864efa5Sthinca 	if (qfp->qf_end_col > 0 && qfp->qf_col != qfp->qf_end_col)
37246864efa5Sthinca 	{
37256864efa5Sthinca 	    vim_snprintf((char *)buf + len, bufsize - len,
37266864efa5Sthinca 		    "-%d", qfp->qf_end_col);
37276864efa5Sthinca 	    len += (int)STRLEN(buf + len);
37286864efa5Sthinca 	}
37296864efa5Sthinca     }
37306864efa5Sthinca     buf[len] = NUL;
37316864efa5Sthinca }
37326864efa5Sthinca 
37336864efa5Sthinca /*
373418cebf44SBram Moolenaar  * Display information (list number, list size and the title) about a
373518cebf44SBram Moolenaar  * quickfix/location list.
373618cebf44SBram Moolenaar  */
3737f6acffbeSBram Moolenaar     static void
qf_msg(qf_info_T * qi,int which,char * lead)3738f6acffbeSBram Moolenaar qf_msg(qf_info_T *qi, int which, char *lead)
3739f6acffbeSBram Moolenaar {
3740f6acffbeSBram Moolenaar     char   *title = (char *)qi->qf_lists[which].qf_title;
3741f6acffbeSBram Moolenaar     int    count = qi->qf_lists[which].qf_count;
3742f6acffbeSBram Moolenaar     char_u buf[IOSIZE];
3743f6acffbeSBram Moolenaar 
3744f6acffbeSBram Moolenaar     vim_snprintf((char *)buf, IOSIZE, _("%serror list %d of %d; %d errors "),
3745f6acffbeSBram Moolenaar 	    lead,
3746f6acffbeSBram Moolenaar 	    which + 1,
3747f6acffbeSBram Moolenaar 	    qi->qf_listcount,
3748f6acffbeSBram Moolenaar 	    count);
3749f6acffbeSBram Moolenaar 
3750f6acffbeSBram Moolenaar     if (title != NULL)
3751f6acffbeSBram Moolenaar     {
375216ec3c9bSBram Moolenaar 	size_t	len = STRLEN(buf);
375316ec3c9bSBram Moolenaar 
375416ec3c9bSBram Moolenaar 	if (len < 34)
375516ec3c9bSBram Moolenaar 	{
375616ec3c9bSBram Moolenaar 	    vim_memset(buf + len, ' ', 34 - len);
375716ec3c9bSBram Moolenaar 	    buf[34] = NUL;
375816ec3c9bSBram Moolenaar 	}
375916ec3c9bSBram Moolenaar 	vim_strcat(buf, (char_u *)title, IOSIZE);
3760f6acffbeSBram Moolenaar     }
3761f6acffbeSBram Moolenaar     trunc_string(buf, buf, Columns - 1, IOSIZE);
376232526b3cSBram Moolenaar     msg((char *)buf);
3763f6acffbeSBram Moolenaar }
3764f6acffbeSBram Moolenaar 
3765071d4279SBram Moolenaar /*
3766071d4279SBram Moolenaar  * ":colder [count]": Up in the quickfix stack.
3767071d4279SBram Moolenaar  * ":cnewer [count]": Down in the quickfix stack.
3768d12f5c17SBram Moolenaar  * ":lolder [count]": Up in the location list stack.
3769d12f5c17SBram Moolenaar  * ":lnewer [count]": Down in the location list stack.
3770071d4279SBram Moolenaar  */
3771071d4279SBram Moolenaar     void
qf_age(exarg_T * eap)377205540976SBram Moolenaar qf_age(exarg_T *eap)
3773071d4279SBram Moolenaar {
377487f59b09SBram Moolenaar     qf_info_T	*qi;
3775071d4279SBram Moolenaar     int		count;
3776071d4279SBram Moolenaar 
377787f59b09SBram Moolenaar     if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
3778d12f5c17SBram Moolenaar 	return;
3779d12f5c17SBram Moolenaar 
3780071d4279SBram Moolenaar     if (eap->addr_count != 0)
3781071d4279SBram Moolenaar 	count = eap->line2;
3782071d4279SBram Moolenaar     else
3783071d4279SBram Moolenaar 	count = 1;
3784071d4279SBram Moolenaar     while (count--)
3785071d4279SBram Moolenaar     {
3786d12f5c17SBram Moolenaar 	if (eap->cmdidx == CMD_colder || eap->cmdidx == CMD_lolder)
3787071d4279SBram Moolenaar 	{
3788d12f5c17SBram Moolenaar 	    if (qi->qf_curlist == 0)
3789071d4279SBram Moolenaar 	    {
3790f9e3e09fSBram Moolenaar 		emsg(_("E380: At bottom of quickfix stack"));
379182e803b0SBram Moolenaar 		break;
3792071d4279SBram Moolenaar 	    }
3793d12f5c17SBram Moolenaar 	    --qi->qf_curlist;
3794071d4279SBram Moolenaar 	}
3795071d4279SBram Moolenaar 	else
3796071d4279SBram Moolenaar 	{
3797d12f5c17SBram Moolenaar 	    if (qi->qf_curlist >= qi->qf_listcount - 1)
3798071d4279SBram Moolenaar 	    {
3799f9e3e09fSBram Moolenaar 		emsg(_("E381: At top of quickfix stack"));
380082e803b0SBram Moolenaar 		break;
3801071d4279SBram Moolenaar 	    }
3802d12f5c17SBram Moolenaar 	    ++qi->qf_curlist;
3803071d4279SBram Moolenaar 	}
3804071d4279SBram Moolenaar     }
3805f6acffbeSBram Moolenaar     qf_msg(qi, qi->qf_curlist, "");
3806864293abSBram Moolenaar     qf_update_buffer(qi, NULL);
3807071d4279SBram Moolenaar }
3808071d4279SBram Moolenaar 
380918cebf44SBram Moolenaar /*
381018cebf44SBram Moolenaar  * Display the information about all the quickfix/location lists in the stack
381118cebf44SBram Moolenaar  */
3812f6acffbeSBram Moolenaar     void
qf_history(exarg_T * eap)3813f6acffbeSBram Moolenaar qf_history(exarg_T *eap)
3814f6acffbeSBram Moolenaar {
381587f59b09SBram Moolenaar     qf_info_T	*qi = qf_cmd_get_stack(eap, FALSE);
3816f6acffbeSBram Moolenaar     int		i;
3817f6acffbeSBram Moolenaar 
38188ffc7c8bSBram Moolenaar     if (eap->addr_count > 0)
38198ffc7c8bSBram Moolenaar     {
38208ffc7c8bSBram Moolenaar 	if (qi == NULL)
38218ffc7c8bSBram Moolenaar 	{
38228ffc7c8bSBram Moolenaar 	    emsg(_(e_loclist));
38238ffc7c8bSBram Moolenaar 	    return;
38248ffc7c8bSBram Moolenaar 	}
38258ffc7c8bSBram Moolenaar 
38268ffc7c8bSBram Moolenaar 	// Jump to the specified quickfix list
38278ffc7c8bSBram Moolenaar 	if (eap->line2 > 0 && eap->line2 <= qi->qf_listcount)
38288ffc7c8bSBram Moolenaar 	{
38298ffc7c8bSBram Moolenaar 	    qi->qf_curlist = eap->line2 - 1;
38308ffc7c8bSBram Moolenaar 	    qf_msg(qi, qi->qf_curlist, "");
38318ffc7c8bSBram Moolenaar 	    qf_update_buffer(qi, NULL);
38328ffc7c8bSBram Moolenaar 	}
38338ffc7c8bSBram Moolenaar 	else
3834108010aaSBram Moolenaar 	    emsg(_(e_invalid_range));
38358ffc7c8bSBram Moolenaar 
38368ffc7c8bSBram Moolenaar 	return;
38378ffc7c8bSBram Moolenaar     }
38388ffc7c8bSBram Moolenaar 
38395b69c22fSBram Moolenaar     if (qf_stack_empty(qi))
384032526b3cSBram Moolenaar 	msg(_("No entries"));
3841f6acffbeSBram Moolenaar     else
3842f6acffbeSBram Moolenaar 	for (i = 0; i < qi->qf_listcount; ++i)
3843f6acffbeSBram Moolenaar 	    qf_msg(qi, i, i == qi->qf_curlist ? "> " : "  ");
3844f6acffbeSBram Moolenaar }
3845f6acffbeSBram Moolenaar 
3846071d4279SBram Moolenaar /*
38476a8958dbSBram Moolenaar  * Free all the entries in the error list "idx". Note that other information
38486a8958dbSBram Moolenaar  * associated with the list like context and title are not freed.
3849071d4279SBram Moolenaar  */
3850071d4279SBram Moolenaar     static void
qf_free_items(qf_list_T * qfl)3851fe15b7dfSBram Moolenaar qf_free_items(qf_list_T *qfl)
3852071d4279SBram Moolenaar {
385368b76a69SBram Moolenaar     qfline_T	*qfp;
385483e6d7acSBram Moolenaar     qfline_T	*qfpnext;
385581484f42SBram Moolenaar     int		stop = FALSE;
3856071d4279SBram Moolenaar 
3857a7df8c70SBram Moolenaar     while (qfl->qf_count && qfl->qf_start != NULL)
3858071d4279SBram Moolenaar     {
3859a7df8c70SBram Moolenaar 	qfp = qfl->qf_start;
386083e6d7acSBram Moolenaar 	qfpnext = qfp->qf_next;
38617adf06f4SBram Moolenaar 	if (!stop)
3862c83a44bfSBram Moolenaar 	{
3863d76ce852SBram Moolenaar 	    vim_free(qfp->qf_module);
386483e6d7acSBram Moolenaar 	    vim_free(qfp->qf_text);
386583e6d7acSBram Moolenaar 	    vim_free(qfp->qf_pattern);
3866d76ce852SBram Moolenaar 	    stop = (qfp == qfpnext);
386783e6d7acSBram Moolenaar 	    vim_free(qfp);
386881484f42SBram Moolenaar 	    if (stop)
386900bf8cd2SBram Moolenaar 		// Somehow qf_count may have an incorrect value, set it to 1
387000bf8cd2SBram Moolenaar 		// to avoid crashing when it's wrong.
387100bf8cd2SBram Moolenaar 		// TODO: Avoid qf_count being incorrect.
3872a7df8c70SBram Moolenaar 		qfl->qf_count = 1;
3873c83a44bfSBram Moolenaar 	}
3874a7df8c70SBram Moolenaar 	qfl->qf_start = qfpnext;
3875a7df8c70SBram Moolenaar 	--qfl->qf_count;
3876071d4279SBram Moolenaar     }
38776a8958dbSBram Moolenaar 
3878a7df8c70SBram Moolenaar     qfl->qf_index = 0;
3879a7df8c70SBram Moolenaar     qfl->qf_start = NULL;
3880a7df8c70SBram Moolenaar     qfl->qf_last = NULL;
3881a7df8c70SBram Moolenaar     qfl->qf_ptr = NULL;
3882a7df8c70SBram Moolenaar     qfl->qf_nonevalid = TRUE;
3883361c8f0eSBram Moolenaar 
3884a7df8c70SBram Moolenaar     qf_clean_dir_stack(&qfl->qf_dir_stack);
3885a7df8c70SBram Moolenaar     qfl->qf_directory = NULL;
3886a7df8c70SBram Moolenaar     qf_clean_dir_stack(&qfl->qf_file_stack);
3887a7df8c70SBram Moolenaar     qfl->qf_currfile = NULL;
3888a7df8c70SBram Moolenaar     qfl->qf_multiline = FALSE;
3889a7df8c70SBram Moolenaar     qfl->qf_multiignore = FALSE;
3890a7df8c70SBram Moolenaar     qfl->qf_multiscan = FALSE;
3891071d4279SBram Moolenaar }
3892071d4279SBram Moolenaar 
3893071d4279SBram Moolenaar /*
38946a8958dbSBram Moolenaar  * Free error list "idx". Frees all the entries in the quickfix list,
38956a8958dbSBram Moolenaar  * associated context information and the title.
38966a8958dbSBram Moolenaar  */
38976a8958dbSBram Moolenaar     static void
qf_free(qf_list_T * qfl)3898fe15b7dfSBram Moolenaar qf_free(qf_list_T *qfl)
38996a8958dbSBram Moolenaar {
3900fe15b7dfSBram Moolenaar     qf_free_items(qfl);
39016a8958dbSBram Moolenaar 
3902d23a8236SBram Moolenaar     VIM_CLEAR(qfl->qf_title);
3903a7df8c70SBram Moolenaar     free_tv(qfl->qf_ctx);
3904a7df8c70SBram Moolenaar     qfl->qf_ctx = NULL;
3905d43906d2SBram Moolenaar     free_callback(&qfl->qftf_cb);
3906a539f4f1SBram Moolenaar     qfl->qf_id = 0;
3907b254af31SBram Moolenaar     qfl->qf_changedtick = 0L;
39086a8958dbSBram Moolenaar }
39096a8958dbSBram Moolenaar 
39106a8958dbSBram Moolenaar /*
3911071d4279SBram Moolenaar  * qf_mark_adjust: adjust marks
3912071d4279SBram Moolenaar  */
3913071d4279SBram Moolenaar    void
qf_mark_adjust(win_T * wp,linenr_T line1,linenr_T line2,long amount,long amount_after)391405540976SBram Moolenaar qf_mark_adjust(
391505540976SBram Moolenaar 	win_T	*wp,
391605540976SBram Moolenaar 	linenr_T	line1,
391705540976SBram Moolenaar 	linenr_T	line2,
391805540976SBram Moolenaar 	long	amount,
391905540976SBram Moolenaar 	long	amount_after)
3920071d4279SBram Moolenaar {
3921071d4279SBram Moolenaar     int		i;
392268b76a69SBram Moolenaar     qfline_T	*qfp;
3923071d4279SBram Moolenaar     int		idx;
3924d12f5c17SBram Moolenaar     qf_info_T	*qi = &ql_info;
39252f095a4bSBram Moolenaar     int		found_one = FALSE;
3926c1542744SBram Moolenaar     int		buf_has_flag = wp == NULL ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
3927071d4279SBram Moolenaar 
3928c1542744SBram Moolenaar     if (!(curbuf->b_has_qf_entry & buf_has_flag))
39292f095a4bSBram Moolenaar 	return;
3930d12f5c17SBram Moolenaar     if (wp != NULL)
3931d12f5c17SBram Moolenaar     {
3932d12f5c17SBram Moolenaar 	if (wp->w_llist == NULL)
3933d12f5c17SBram Moolenaar 	    return;
3934d12f5c17SBram Moolenaar 	qi = wp->w_llist;
3935d12f5c17SBram Moolenaar     }
3936d12f5c17SBram Moolenaar 
3937d12f5c17SBram Moolenaar     for (idx = 0; idx < qi->qf_listcount; ++idx)
39380398e00aSBram Moolenaar     {
39390398e00aSBram Moolenaar 	qf_list_T	*qfl = qf_get_list(qi, idx);
39400398e00aSBram Moolenaar 
39410398e00aSBram Moolenaar 	if (!qf_list_empty(qfl))
3942a16123a6SBram Moolenaar 	    FOR_ALL_QFL_ITEMS(qfl, qfp, i)
3943071d4279SBram Moolenaar 		if (qfp->qf_fnum == curbuf->b_fnum)
3944071d4279SBram Moolenaar 		{
39452f095a4bSBram Moolenaar 		    found_one = TRUE;
3946071d4279SBram Moolenaar 		    if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2)
3947071d4279SBram Moolenaar 		    {
3948071d4279SBram Moolenaar 			if (amount == MAXLNUM)
3949071d4279SBram Moolenaar 			    qfp->qf_cleared = TRUE;
3950071d4279SBram Moolenaar 			else
3951071d4279SBram Moolenaar 			    qfp->qf_lnum += amount;
3952071d4279SBram Moolenaar 		    }
3953071d4279SBram Moolenaar 		    else if (amount_after && qfp->qf_lnum > line2)
3954071d4279SBram Moolenaar 			qfp->qf_lnum += amount_after;
3955071d4279SBram Moolenaar 		}
39560398e00aSBram Moolenaar     }
39572f095a4bSBram Moolenaar 
39582f095a4bSBram Moolenaar     if (!found_one)
3959c1542744SBram Moolenaar 	curbuf->b_has_qf_entry &= ~buf_has_flag;
3960071d4279SBram Moolenaar }
3961071d4279SBram Moolenaar 
3962071d4279SBram Moolenaar /*
3963071d4279SBram Moolenaar  * Make a nice message out of the error character and the error number:
3964071d4279SBram Moolenaar  *  char    number	message
3965071d4279SBram Moolenaar  *  e or E    0		" error"
3966071d4279SBram Moolenaar  *  w or W    0		" warning"
3967071d4279SBram Moolenaar  *  i or I    0		" info"
3968e928366dSBram Moolenaar  *  n or N    0		" note"
3969071d4279SBram Moolenaar  *  0	      0		""
3970071d4279SBram Moolenaar  *  other     0		" c"
3971071d4279SBram Moolenaar  *  e or E    n		" error n"
3972071d4279SBram Moolenaar  *  w or W    n		" warning n"
3973071d4279SBram Moolenaar  *  i or I    n		" info n"
3974e928366dSBram Moolenaar  *  n or N    n		" note n"
3975071d4279SBram Moolenaar  *  0	      n		" error n"
3976071d4279SBram Moolenaar  *  other     n		" c n"
3977071d4279SBram Moolenaar  *  1	      x		""	:helpgrep
3978071d4279SBram Moolenaar  */
3979071d4279SBram Moolenaar     static char_u *
qf_types(int c,int nr)398005540976SBram Moolenaar qf_types(int c, int nr)
3981071d4279SBram Moolenaar {
3982071d4279SBram Moolenaar     static char_u	buf[20];
3983071d4279SBram Moolenaar     static char_u	cc[3];
3984071d4279SBram Moolenaar     char_u		*p;
3985071d4279SBram Moolenaar 
3986071d4279SBram Moolenaar     if (c == 'W' || c == 'w')
3987071d4279SBram Moolenaar 	p = (char_u *)" warning";
3988071d4279SBram Moolenaar     else if (c == 'I' || c == 'i')
3989071d4279SBram Moolenaar 	p = (char_u *)" info";
3990e928366dSBram Moolenaar     else if (c == 'N' || c == 'n')
3991e928366dSBram Moolenaar 	p = (char_u *)" note";
3992071d4279SBram Moolenaar     else if (c == 'E' || c == 'e' || (c == 0 && nr > 0))
3993071d4279SBram Moolenaar 	p = (char_u *)" error";
3994071d4279SBram Moolenaar     else if (c == 0 || c == 1)
3995071d4279SBram Moolenaar 	p = (char_u *)"";
3996071d4279SBram Moolenaar     else
3997071d4279SBram Moolenaar     {
3998071d4279SBram Moolenaar 	cc[0] = ' ';
3999071d4279SBram Moolenaar 	cc[1] = c;
4000071d4279SBram Moolenaar 	cc[2] = NUL;
4001071d4279SBram Moolenaar 	p = cc;
4002071d4279SBram Moolenaar     }
4003071d4279SBram Moolenaar 
4004071d4279SBram Moolenaar     if (nr <= 0)
4005071d4279SBram Moolenaar 	return p;
4006071d4279SBram Moolenaar 
4007071d4279SBram Moolenaar     sprintf((char *)buf, "%s %3d", (char *)p, nr);
4008071d4279SBram Moolenaar     return buf;
4009071d4279SBram Moolenaar }
4010071d4279SBram Moolenaar 
4011071d4279SBram Moolenaar /*
40120a08c63dSBram Moolenaar  * When "split" is FALSE: Open the entry/result under the cursor.
40130a08c63dSBram Moolenaar  * When "split" is TRUE: Open the entry/result under the cursor in a new window.
40140a08c63dSBram Moolenaar  */
40150a08c63dSBram Moolenaar     void
qf_view_result(int split)40160a08c63dSBram Moolenaar qf_view_result(int split)
40170a08c63dSBram Moolenaar {
40180a08c63dSBram Moolenaar     qf_info_T   *qi = &ql_info;
40190a08c63dSBram Moolenaar 
40200a08c63dSBram Moolenaar     if (!bt_quickfix(curbuf))
40210a08c63dSBram Moolenaar 	return;
40220a08c63dSBram Moolenaar 
40230a08c63dSBram Moolenaar     if (IS_LL_WINDOW(curwin))
40240a08c63dSBram Moolenaar 	qi = GET_LOC_LIST(curwin);
40250a08c63dSBram Moolenaar 
40260398e00aSBram Moolenaar     if (qf_list_empty(qf_get_curlist(qi)))
40270a08c63dSBram Moolenaar     {
4028e29a27f6SBram Moolenaar 	emsg(_(e_no_errors));
40290a08c63dSBram Moolenaar 	return;
40300a08c63dSBram Moolenaar     }
40310a08c63dSBram Moolenaar 
40320a08c63dSBram Moolenaar     if (split)
40330a08c63dSBram Moolenaar     {
4034b244373bSBram Moolenaar 	// Open the selected entry in a new window
4035b244373bSBram Moolenaar 	qf_jump_newwin(qi, 0, (long)curwin->w_cursor.lnum, FALSE, TRUE);
40360a08c63dSBram Moolenaar 	do_cmdline_cmd((char_u *) "clearjumps");
40370a08c63dSBram Moolenaar 	return;
40380a08c63dSBram Moolenaar     }
40390a08c63dSBram Moolenaar 
40400a08c63dSBram Moolenaar     do_cmdline_cmd((char_u *)(IS_LL_WINDOW(curwin) ? ".ll" : ".cc"));
40410a08c63dSBram Moolenaar }
40420a08c63dSBram Moolenaar 
40430a08c63dSBram Moolenaar /*
4044071d4279SBram Moolenaar  * ":cwindow": open the quickfix window if we have errors to display,
4045071d4279SBram Moolenaar  *	       close it if not.
4046d12f5c17SBram Moolenaar  * ":lwindow": open the location list window if we have locations to display,
4047d12f5c17SBram Moolenaar  *	       close it if not.
4048071d4279SBram Moolenaar  */
4049071d4279SBram Moolenaar     void
ex_cwindow(exarg_T * eap)405005540976SBram Moolenaar ex_cwindow(exarg_T *eap)
4051071d4279SBram Moolenaar {
405287f59b09SBram Moolenaar     qf_info_T	*qi;
4053108e7b42SBram Moolenaar     qf_list_T	*qfl;
4054071d4279SBram Moolenaar     win_T	*win;
4055071d4279SBram Moolenaar 
405687f59b09SBram Moolenaar     if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
4057d12f5c17SBram Moolenaar 	return;
4058d12f5c17SBram Moolenaar 
40594aa47b28SBram Moolenaar     qfl = qf_get_curlist(qi);
4060108e7b42SBram Moolenaar 
406100bf8cd2SBram Moolenaar     // Look for an existing quickfix window.
4062d12f5c17SBram Moolenaar     win = qf_find_win(qi);
4063071d4279SBram Moolenaar 
406400bf8cd2SBram Moolenaar     // If a quickfix window is open but we have no errors to display,
406500bf8cd2SBram Moolenaar     // close the window.  If a quickfix window is not open, then open
406600bf8cd2SBram Moolenaar     // it if we have errors; otherwise, leave it closed.
4067019dfe68SBram Moolenaar     if (qf_stack_empty(qi)
4068108e7b42SBram Moolenaar 	    || qfl->qf_nonevalid
40699afe5e9cSBram Moolenaar 	    || qf_list_empty(qfl))
4070071d4279SBram Moolenaar     {
4071071d4279SBram Moolenaar 	if (win != NULL)
4072071d4279SBram Moolenaar 	    ex_cclose(eap);
4073071d4279SBram Moolenaar     }
4074071d4279SBram Moolenaar     else if (win == NULL)
4075071d4279SBram Moolenaar 	ex_copen(eap);
4076071d4279SBram Moolenaar }
4077071d4279SBram Moolenaar 
4078071d4279SBram Moolenaar /*
4079071d4279SBram Moolenaar  * ":cclose": close the window showing the list of errors.
4080d12f5c17SBram Moolenaar  * ":lclose": close the window showing the location list
4081071d4279SBram Moolenaar  */
4082071d4279SBram Moolenaar     void
ex_cclose(exarg_T * eap)408305540976SBram Moolenaar ex_cclose(exarg_T *eap)
4084071d4279SBram Moolenaar {
4085d12f5c17SBram Moolenaar     win_T	*win = NULL;
408687f59b09SBram Moolenaar     qf_info_T	*qi;
4087071d4279SBram Moolenaar 
408887f59b09SBram Moolenaar     if ((qi = qf_cmd_get_stack(eap, FALSE)) == NULL)
4089d12f5c17SBram Moolenaar 	return;
4090071d4279SBram Moolenaar 
409100bf8cd2SBram Moolenaar     // Find existing quickfix window and close it.
4092d12f5c17SBram Moolenaar     win = qf_find_win(qi);
4093071d4279SBram Moolenaar     if (win != NULL)
4094071d4279SBram Moolenaar 	win_close(win, FALSE);
4095071d4279SBram Moolenaar }
4096071d4279SBram Moolenaar 
4097071d4279SBram Moolenaar /*
4098fe15b7dfSBram Moolenaar  * Set "w:quickfix_title" if "qi" has a title.
4099fe15b7dfSBram Moolenaar  */
4100fe15b7dfSBram Moolenaar     static void
qf_set_title_var(qf_list_T * qfl)4101fe15b7dfSBram Moolenaar qf_set_title_var(qf_list_T *qfl)
4102fe15b7dfSBram Moolenaar {
4103fe15b7dfSBram Moolenaar     if (qfl->qf_title != NULL)
4104fe15b7dfSBram Moolenaar 	set_internal_string_var((char_u *)"w:quickfix_title", qfl->qf_title);
4105fe15b7dfSBram Moolenaar }
4106fe15b7dfSBram Moolenaar 
4107fe15b7dfSBram Moolenaar /*
4108476c0db0SBram Moolenaar  * Goto a quickfix or location list window (if present).
4109476c0db0SBram Moolenaar  * Returns OK if the window is found, FAIL otherwise.
4110476c0db0SBram Moolenaar  */
4111476c0db0SBram Moolenaar     static int
qf_goto_cwindow(qf_info_T * qi,int resize,int sz,int vertsplit)4112476c0db0SBram Moolenaar qf_goto_cwindow(qf_info_T *qi, int resize, int sz, int vertsplit)
4113476c0db0SBram Moolenaar {
4114476c0db0SBram Moolenaar     win_T	*win;
4115476c0db0SBram Moolenaar 
4116476c0db0SBram Moolenaar     win = qf_find_win(qi);
4117476c0db0SBram Moolenaar     if (win == NULL)
4118476c0db0SBram Moolenaar 	return FAIL;
4119476c0db0SBram Moolenaar 
4120476c0db0SBram Moolenaar     win_goto(win);
4121476c0db0SBram Moolenaar     if (resize)
4122476c0db0SBram Moolenaar     {
4123476c0db0SBram Moolenaar 	if (vertsplit)
4124476c0db0SBram Moolenaar 	{
4125476c0db0SBram Moolenaar 	    if (sz != win->w_width)
4126476c0db0SBram Moolenaar 		win_setwidth(sz);
4127476c0db0SBram Moolenaar 	}
41281142a31bSBram Moolenaar 	else if (sz != win->w_height && win->w_height
41291142a31bSBram Moolenaar 		       + win->w_status_height + tabline_height() < cmdline_row)
4130476c0db0SBram Moolenaar 	    win_setheight(sz);
4131476c0db0SBram Moolenaar     }
4132476c0db0SBram Moolenaar 
4133476c0db0SBram Moolenaar     return OK;
4134476c0db0SBram Moolenaar }
4135476c0db0SBram Moolenaar 
4136476c0db0SBram Moolenaar /*
4137d82a81caSBram Moolenaar  * Set options for the buffer in the quickfix or location list window.
4138d82a81caSBram Moolenaar  */
4139d82a81caSBram Moolenaar     static void
qf_set_cwindow_options(void)4140d82a81caSBram Moolenaar qf_set_cwindow_options(void)
4141d82a81caSBram Moolenaar {
4142d82a81caSBram Moolenaar     // switch off 'swapfile'
4143d82a81caSBram Moolenaar     set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
4144d82a81caSBram Moolenaar     set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix",
4145d82a81caSBram Moolenaar 	    OPT_LOCAL);
4146d82a81caSBram Moolenaar     set_option_value((char_u *)"bh", 0L, (char_u *)"hide", OPT_LOCAL);
4147d82a81caSBram Moolenaar     RESET_BINDING(curwin);
4148d82a81caSBram Moolenaar #ifdef FEAT_DIFF
4149d82a81caSBram Moolenaar     curwin->w_p_diff = FALSE;
4150d82a81caSBram Moolenaar #endif
4151d82a81caSBram Moolenaar #ifdef FEAT_FOLDING
4152d82a81caSBram Moolenaar     set_option_value((char_u *)"fdm", 0L, (char_u *)"manual",
4153d82a81caSBram Moolenaar 	    OPT_LOCAL);
4154d82a81caSBram Moolenaar #endif
4155d82a81caSBram Moolenaar }
4156d82a81caSBram Moolenaar 
4157d82a81caSBram Moolenaar /*
4158476c0db0SBram Moolenaar  * Open a new quickfix or location list window, load the quickfix buffer and
4159476c0db0SBram Moolenaar  * set the appropriate options for the window.
4160476c0db0SBram Moolenaar  * Returns FAIL if the window could not be opened.
4161476c0db0SBram Moolenaar  */
4162476c0db0SBram Moolenaar     static int
qf_open_new_cwindow(qf_info_T * qi,int height)4163476c0db0SBram Moolenaar qf_open_new_cwindow(qf_info_T *qi, int height)
4164476c0db0SBram Moolenaar {
4165476c0db0SBram Moolenaar     buf_T	*qf_buf;
4166476c0db0SBram Moolenaar     win_T	*oldwin = curwin;
4167476c0db0SBram Moolenaar     tabpage_T	*prevtab = curtab;
4168476c0db0SBram Moolenaar     int		flags = 0;
4169476c0db0SBram Moolenaar     win_T	*win;
4170476c0db0SBram Moolenaar 
4171476c0db0SBram Moolenaar     qf_buf = qf_find_buf(qi);
4172476c0db0SBram Moolenaar 
4173476c0db0SBram Moolenaar     // The current window becomes the previous window afterwards.
4174476c0db0SBram Moolenaar     win = curwin;
4175476c0db0SBram Moolenaar 
4176e1004401SBram Moolenaar     if (IS_QF_STACK(qi) && cmdmod.cmod_split == 0)
4177476c0db0SBram Moolenaar 	// Create the new quickfix window at the very bottom, except when
4178476c0db0SBram Moolenaar 	// :belowright or :aboveleft is used.
4179476c0db0SBram Moolenaar 	win_goto(lastwin);
4180476c0db0SBram Moolenaar     // Default is to open the window below the current window
4181e1004401SBram Moolenaar     if (cmdmod.cmod_split == 0)
4182476c0db0SBram Moolenaar 	flags = WSP_BELOW;
4183476c0db0SBram Moolenaar     flags |= WSP_NEWLOC;
4184476c0db0SBram Moolenaar     if (win_split(height, flags) == FAIL)
4185476c0db0SBram Moolenaar 	return FAIL;		// not enough room for window
4186476c0db0SBram Moolenaar     RESET_BINDING(curwin);
4187476c0db0SBram Moolenaar 
4188476c0db0SBram Moolenaar     if (IS_LL_STACK(qi))
4189476c0db0SBram Moolenaar     {
4190476c0db0SBram Moolenaar 	// For the location list window, create a reference to the
4191eeb1b9c7SBram Moolenaar 	// location list stack from the window 'win'.
4192eeb1b9c7SBram Moolenaar 	curwin->w_llist_ref = qi;
4193eeb1b9c7SBram Moolenaar 	qi->qf_refcount++;
4194476c0db0SBram Moolenaar     }
4195476c0db0SBram Moolenaar 
4196476c0db0SBram Moolenaar     if (oldwin != curwin)
4197476c0db0SBram Moolenaar 	oldwin = NULL;  // don't store info when in another window
4198476c0db0SBram Moolenaar     if (qf_buf != NULL)
4199476c0db0SBram Moolenaar     {
4200476c0db0SBram Moolenaar 	// Use the existing quickfix buffer
42019e40c4b1SBram Moolenaar 	if (do_ecmd(qf_buf->b_fnum, NULL, NULL, NULL, ECMD_ONE,
42021d30fde3SBram Moolenaar 		    ECMD_HIDE + ECMD_OLDBUF + ECMD_NOWINENTER, oldwin) == FAIL)
42039e40c4b1SBram Moolenaar 	    return FAIL;
4204476c0db0SBram Moolenaar     }
4205476c0db0SBram Moolenaar     else
4206476c0db0SBram Moolenaar     {
4207476c0db0SBram Moolenaar 	// Create a new quickfix buffer
42081d30fde3SBram Moolenaar 	if (do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE + ECMD_NOWINENTER,
42091d30fde3SBram Moolenaar 							       oldwin) == FAIL)
42109e40c4b1SBram Moolenaar 	    return FAIL;
4211476c0db0SBram Moolenaar 
4212ee8188fcSBram Moolenaar 	// save the number of the new buffer
4213ee8188fcSBram Moolenaar 	qi->qf_bufnr = curbuf->b_fnum;
4214476c0db0SBram Moolenaar     }
4215476c0db0SBram Moolenaar 
4216d82a81caSBram Moolenaar     // Set the options for the quickfix buffer/window (if not already done)
4217d82a81caSBram Moolenaar     // Do this even if the quickfix buffer was already present, as an autocmd
4218d82a81caSBram Moolenaar     // might have previously deleted (:bdelete) the quickfix buffer.
421961eeeea8SBram Moolenaar     if (!bt_quickfix(curbuf))
4220d82a81caSBram Moolenaar 	qf_set_cwindow_options();
4221d82a81caSBram Moolenaar 
4222476c0db0SBram Moolenaar     // Only set the height when still in the same tab page and there is no
4223476c0db0SBram Moolenaar     // window to the side.
4224476c0db0SBram Moolenaar     if (curtab == prevtab && curwin->w_width == Columns)
4225476c0db0SBram Moolenaar 	win_setheight(height);
4226476c0db0SBram Moolenaar     curwin->w_p_wfh = TRUE;	    // set 'winfixheight'
4227476c0db0SBram Moolenaar     if (win_valid(win))
4228476c0db0SBram Moolenaar 	prevwin = win;
4229476c0db0SBram Moolenaar 
4230476c0db0SBram Moolenaar     return OK;
4231476c0db0SBram Moolenaar }
4232476c0db0SBram Moolenaar 
4233476c0db0SBram Moolenaar /*
4234071d4279SBram Moolenaar  * ":copen": open a window that shows the list of errors.
4235d12f5c17SBram Moolenaar  * ":lopen": open a window that shows the location list.
4236071d4279SBram Moolenaar  */
4237071d4279SBram Moolenaar     void
ex_copen(exarg_T * eap)423805540976SBram Moolenaar ex_copen(exarg_T *eap)
4239071d4279SBram Moolenaar {
424087f59b09SBram Moolenaar     qf_info_T	*qi;
4241108e7b42SBram Moolenaar     qf_list_T	*qfl;
4242071d4279SBram Moolenaar     int		height;
4243476c0db0SBram Moolenaar     int		status = FAIL;
42449f84ded3SBram Moolenaar     int		lnum;
4245071d4279SBram Moolenaar 
424687f59b09SBram Moolenaar     if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
4247d12f5c17SBram Moolenaar 	return;
4248d12f5c17SBram Moolenaar 
42499f84ded3SBram Moolenaar     incr_quickfix_busy();
42509f84ded3SBram Moolenaar 
4251071d4279SBram Moolenaar     if (eap->addr_count != 0)
4252071d4279SBram Moolenaar 	height = eap->line2;
4253071d4279SBram Moolenaar     else
4254071d4279SBram Moolenaar 	height = QF_WINHEIGHT;
4255071d4279SBram Moolenaar 
4256476c0db0SBram Moolenaar     reset_VIsual_and_resel();			// stop Visual mode
4257071d4279SBram Moolenaar #ifdef FEAT_GUI
4258071d4279SBram Moolenaar     need_mouse_correct = TRUE;
4259071d4279SBram Moolenaar #endif
4260071d4279SBram Moolenaar 
4261476c0db0SBram Moolenaar     // Find an existing quickfix window, or open a new one.
4262e1004401SBram Moolenaar     if (cmdmod.cmod_tab == 0)
4263476c0db0SBram Moolenaar 	status = qf_goto_cwindow(qi, eap->addr_count != 0, height,
4264e1004401SBram Moolenaar 						cmdmod.cmod_split & WSP_VERT);
4265476c0db0SBram Moolenaar     if (status == FAIL)
4266476c0db0SBram Moolenaar 	if (qf_open_new_cwindow(qi, height) == FAIL)
42679f84ded3SBram Moolenaar 	{
42689f84ded3SBram Moolenaar 	    decr_quickfix_busy();
4269476c0db0SBram Moolenaar 	    return;
42709f84ded3SBram Moolenaar 	}
4271071d4279SBram Moolenaar 
42724aa47b28SBram Moolenaar     qfl = qf_get_curlist(qi);
4273108e7b42SBram Moolenaar     qf_set_title_var(qfl);
42749f84ded3SBram Moolenaar     // Save the current index here, as updating the quickfix buffer may free
42759f84ded3SBram Moolenaar     // the quickfix list
42769f84ded3SBram Moolenaar     lnum = qfl->qf_index;
427781278efaSBram Moolenaar 
4278476c0db0SBram Moolenaar     // Fill the buffer with the quickfix list.
42797ba5a7efSBram Moolenaar     qf_fill_buffer(qfl, curbuf, NULL, curwin->w_id);
4280071d4279SBram Moolenaar 
42819f84ded3SBram Moolenaar     decr_quickfix_busy();
42829f84ded3SBram Moolenaar 
42839f84ded3SBram Moolenaar     curwin->w_cursor.lnum = lnum;
4284071d4279SBram Moolenaar     curwin->w_cursor.col = 0;
4285071d4279SBram Moolenaar     check_cursor();
4286476c0db0SBram Moolenaar     update_topline();		// scroll to show the line
4287071d4279SBram Moolenaar }
4288071d4279SBram Moolenaar 
4289071d4279SBram Moolenaar /*
4290dcb17001SBram Moolenaar  * Move the cursor in the quickfix window to "lnum".
4291dcb17001SBram Moolenaar  */
4292dcb17001SBram Moolenaar     static void
qf_win_goto(win_T * win,linenr_T lnum)4293dcb17001SBram Moolenaar qf_win_goto(win_T *win, linenr_T lnum)
4294dcb17001SBram Moolenaar {
4295dcb17001SBram Moolenaar     win_T	*old_curwin = curwin;
4296dcb17001SBram Moolenaar 
4297dcb17001SBram Moolenaar     curwin = win;
4298dcb17001SBram Moolenaar     curbuf = win->w_buffer;
4299dcb17001SBram Moolenaar     curwin->w_cursor.lnum = lnum;
4300dcb17001SBram Moolenaar     curwin->w_cursor.col = 0;
4301dcb17001SBram Moolenaar     curwin->w_cursor.coladd = 0;
4302dcb17001SBram Moolenaar     curwin->w_curswant = 0;
430300bf8cd2SBram Moolenaar     update_topline();		// scroll to show the line
4304dcb17001SBram Moolenaar     redraw_later(VALID);
430500bf8cd2SBram Moolenaar     curwin->w_redr_status = TRUE;	// update ruler
4306dcb17001SBram Moolenaar     curwin = old_curwin;
4307dcb17001SBram Moolenaar     curbuf = curwin->w_buffer;
4308dcb17001SBram Moolenaar }
4309dcb17001SBram Moolenaar 
4310dcb17001SBram Moolenaar /*
4311537ef084SBram Moolenaar  * :cbottom/:lbottom commands.
4312dcb17001SBram Moolenaar  */
4313dcb17001SBram Moolenaar     void
ex_cbottom(exarg_T * eap)431439665959SBram Moolenaar ex_cbottom(exarg_T *eap)
4315dcb17001SBram Moolenaar {
431687f59b09SBram Moolenaar     qf_info_T	*qi;
4317537ef084SBram Moolenaar     win_T	*win;
4318dcb17001SBram Moolenaar 
431987f59b09SBram Moolenaar     if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
4320537ef084SBram Moolenaar 	return;
4321537ef084SBram Moolenaar 
4322537ef084SBram Moolenaar     win = qf_find_win(qi);
4323dcb17001SBram Moolenaar     if (win != NULL && win->w_cursor.lnum != win->w_buffer->b_ml.ml_line_count)
4324dcb17001SBram Moolenaar 	qf_win_goto(win, win->w_buffer->b_ml.ml_line_count);
4325dcb17001SBram Moolenaar }
4326dcb17001SBram Moolenaar 
4327dcb17001SBram Moolenaar /*
4328071d4279SBram Moolenaar  * Return the number of the current entry (line number in the quickfix
4329071d4279SBram Moolenaar  * window).
4330071d4279SBram Moolenaar  */
4331071d4279SBram Moolenaar      linenr_T
qf_current_entry(win_T * wp)433205540976SBram Moolenaar qf_current_entry(win_T *wp)
4333071d4279SBram Moolenaar {
4334d12f5c17SBram Moolenaar     qf_info_T	*qi = &ql_info;
4335d12f5c17SBram Moolenaar 
4336d12f5c17SBram Moolenaar     if (IS_LL_WINDOW(wp))
433700bf8cd2SBram Moolenaar 	// In the location list window, use the referenced location list
4338d12f5c17SBram Moolenaar 	qi = wp->w_llist_ref;
4339d12f5c17SBram Moolenaar 
43404aa47b28SBram Moolenaar     return qf_get_curlist(qi)->qf_index;
4341071d4279SBram Moolenaar }
4342071d4279SBram Moolenaar 
4343071d4279SBram Moolenaar /*
4344071d4279SBram Moolenaar  * Update the cursor position in the quickfix window to the current error.
4345071d4279SBram Moolenaar  * Return TRUE if there is a quickfix window.
4346071d4279SBram Moolenaar  */
4347071d4279SBram Moolenaar     static int
qf_win_pos_update(qf_info_T * qi,int old_qf_index)434805540976SBram Moolenaar qf_win_pos_update(
434905540976SBram Moolenaar     qf_info_T	*qi,
435000bf8cd2SBram Moolenaar     int		old_qf_index)	// previous qf_index or zero
4351071d4279SBram Moolenaar {
4352071d4279SBram Moolenaar     win_T	*win;
43534aa47b28SBram Moolenaar     int		qf_index = qf_get_curlist(qi)->qf_index;
4354071d4279SBram Moolenaar 
435500bf8cd2SBram Moolenaar     // Put the cursor on the current error in the quickfix window, so that
435600bf8cd2SBram Moolenaar     // it's viewable.
4357d12f5c17SBram Moolenaar     win = qf_find_win(qi);
4358071d4279SBram Moolenaar     if (win != NULL
4359071d4279SBram Moolenaar 	    && qf_index <= win->w_buffer->b_ml.ml_line_count
4360071d4279SBram Moolenaar 	    && old_qf_index != qf_index)
4361071d4279SBram Moolenaar     {
4362071d4279SBram Moolenaar 	if (qf_index > old_qf_index)
4363071d4279SBram Moolenaar 	{
4364dcb17001SBram Moolenaar 	    win->w_redraw_top = old_qf_index;
4365dcb17001SBram Moolenaar 	    win->w_redraw_bot = qf_index;
4366071d4279SBram Moolenaar 	}
4367071d4279SBram Moolenaar 	else
4368071d4279SBram Moolenaar 	{
4369dcb17001SBram Moolenaar 	    win->w_redraw_top = qf_index;
4370dcb17001SBram Moolenaar 	    win->w_redraw_bot = old_qf_index;
4371071d4279SBram Moolenaar 	}
4372dcb17001SBram Moolenaar 	qf_win_goto(win, qf_index);
4373071d4279SBram Moolenaar     }
4374071d4279SBram Moolenaar     return win != NULL;
4375071d4279SBram Moolenaar }
4376071d4279SBram Moolenaar 
4377071d4279SBram Moolenaar /*
43789c102387SBram Moolenaar  * Check whether the given window is displaying the specified quickfix/location
4379fe15b7dfSBram Moolenaar  * stack.
43809c102387SBram Moolenaar  */
43819c102387SBram Moolenaar     static int
is_qf_win(win_T * win,qf_info_T * qi)438205540976SBram Moolenaar is_qf_win(win_T *win, qf_info_T *qi)
43839c102387SBram Moolenaar {
438400bf8cd2SBram Moolenaar     // A window displaying the quickfix buffer will have the w_llist_ref field
438500bf8cd2SBram Moolenaar     // set to NULL.
438600bf8cd2SBram Moolenaar     // A window displaying a location list buffer will have the w_llist_ref
438700bf8cd2SBram Moolenaar     // pointing to the location list.
43889c102387SBram Moolenaar     if (bt_quickfix(win->w_buffer))
43894d77c65aSBram Moolenaar 	if ((IS_QF_STACK(qi) && win->w_llist_ref == NULL)
43904d77c65aSBram Moolenaar 		|| (IS_LL_STACK(qi) && win->w_llist_ref == qi))
43919c102387SBram Moolenaar 	    return TRUE;
43929c102387SBram Moolenaar 
43939c102387SBram Moolenaar     return FALSE;
43949c102387SBram Moolenaar }
43959c102387SBram Moolenaar 
43969c102387SBram Moolenaar /*
4397fe15b7dfSBram Moolenaar  * Find a window displaying the quickfix/location stack 'qi'
43982ec364e9SBram Moolenaar  * Only searches in the current tabpage.
4399d12f5c17SBram Moolenaar  */
4400d12f5c17SBram Moolenaar     static win_T *
qf_find_win(qf_info_T * qi)440105540976SBram Moolenaar qf_find_win(qf_info_T *qi)
4402d12f5c17SBram Moolenaar {
4403d12f5c17SBram Moolenaar     win_T	*win;
4404d12f5c17SBram Moolenaar 
4405d12f5c17SBram Moolenaar     FOR_ALL_WINDOWS(win)
44069c102387SBram Moolenaar 	if (is_qf_win(win, qi))
4407d12f5c17SBram Moolenaar 	    return win;
44082ec364e9SBram Moolenaar     return NULL;
4409d12f5c17SBram Moolenaar }
4410d12f5c17SBram Moolenaar 
4411d12f5c17SBram Moolenaar /*
44129c102387SBram Moolenaar  * Find a quickfix buffer.
44139c102387SBram Moolenaar  * Searches in windows opened in all the tabs.
4414071d4279SBram Moolenaar  */
4415071d4279SBram Moolenaar     static buf_T *
qf_find_buf(qf_info_T * qi)441605540976SBram Moolenaar qf_find_buf(qf_info_T *qi)
4417071d4279SBram Moolenaar {
44189c102387SBram Moolenaar     tabpage_T	*tp;
4419d12f5c17SBram Moolenaar     win_T	*win;
4420071d4279SBram Moolenaar 
4421ee8188fcSBram Moolenaar     if (qi->qf_bufnr != INVALID_QFBUFNR)
4422ee8188fcSBram Moolenaar     {
4423ee8188fcSBram Moolenaar 	buf_T	*qfbuf;
4424ee8188fcSBram Moolenaar 	qfbuf = buflist_findnr(qi->qf_bufnr);
4425ee8188fcSBram Moolenaar 	if (qfbuf != NULL)
4426ee8188fcSBram Moolenaar 	    return qfbuf;
4427ee8188fcSBram Moolenaar 	// buffer is no longer present
4428ee8188fcSBram Moolenaar 	qi->qf_bufnr = INVALID_QFBUFNR;
4429ee8188fcSBram Moolenaar     }
4430ee8188fcSBram Moolenaar 
44319c102387SBram Moolenaar     FOR_ALL_TAB_WINDOWS(tp, win)
44329c102387SBram Moolenaar 	if (is_qf_win(win, qi))
44339c102387SBram Moolenaar 	    return win->w_buffer;
4434d12f5c17SBram Moolenaar 
44359c102387SBram Moolenaar     return NULL;
4436071d4279SBram Moolenaar }
4437071d4279SBram Moolenaar 
4438071d4279SBram Moolenaar /*
4439d43906d2SBram Moolenaar  * Process the 'quickfixtextfunc' option value.
4440*777175b0SYegappan Lakshmanan  * Returns OK or FAIL.
4441d43906d2SBram Moolenaar  */
4442d43906d2SBram Moolenaar     int
qf_process_qftf_option(void)4443d43906d2SBram Moolenaar qf_process_qftf_option(void)
4444d43906d2SBram Moolenaar {
4445*777175b0SYegappan Lakshmanan     return option_set_callback_func(p_qftf, &qftf_cb);
4446d43906d2SBram Moolenaar }
4447d43906d2SBram Moolenaar 
4448d43906d2SBram Moolenaar /*
4449530bed99SBram Moolenaar  * Update the w:quickfix_title variable in the quickfix/location list window in
4450530bed99SBram Moolenaar  * all the tab pages.
4451d823fa91SBram Moolenaar  */
4452d823fa91SBram Moolenaar     static void
qf_update_win_titlevar(qf_info_T * qi)4453d823fa91SBram Moolenaar qf_update_win_titlevar(qf_info_T *qi)
4454d823fa91SBram Moolenaar {
4455530bed99SBram Moolenaar     qf_list_T	*qfl = qf_get_curlist(qi);
4456530bed99SBram Moolenaar     tabpage_T	*tp;
4457d823fa91SBram Moolenaar     win_T	*win;
4458530bed99SBram Moolenaar     win_T	*save_curwin = curwin;
4459d823fa91SBram Moolenaar 
4460530bed99SBram Moolenaar     FOR_ALL_TAB_WINDOWS(tp, win)
4461d823fa91SBram Moolenaar     {
4462530bed99SBram Moolenaar 	if (is_qf_win(win, qi))
4463530bed99SBram Moolenaar 	{
4464d823fa91SBram Moolenaar 	    curwin = win;
4465530bed99SBram Moolenaar 	    qf_set_title_var(qfl);
4466d823fa91SBram Moolenaar 	}
4467d823fa91SBram Moolenaar     }
4468530bed99SBram Moolenaar     curwin = save_curwin;
4469530bed99SBram Moolenaar }
4470d823fa91SBram Moolenaar 
4471d823fa91SBram Moolenaar /*
4472071d4279SBram Moolenaar  * Find the quickfix buffer.  If it exists, update the contents.
4473071d4279SBram Moolenaar  */
4474071d4279SBram Moolenaar     static void
qf_update_buffer(qf_info_T * qi,qfline_T * old_last)4475864293abSBram Moolenaar qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
4476071d4279SBram Moolenaar {
4477071d4279SBram Moolenaar     buf_T	*buf;
4478c95e3263SBram Moolenaar     win_T	*win;
4479071d4279SBram Moolenaar     aco_save_T	aco;
4480071d4279SBram Moolenaar 
448100bf8cd2SBram Moolenaar     // Check if a buffer for the quickfix list exists.  Update it.
4482d12f5c17SBram Moolenaar     buf = qf_find_buf(qi);
4483071d4279SBram Moolenaar     if (buf != NULL)
4484071d4279SBram Moolenaar     {
4485864293abSBram Moolenaar 	linenr_T	old_line_count = buf->b_ml.ml_line_count;
44867ba5a7efSBram Moolenaar 	int		qf_winid = 0;
44877ba5a7efSBram Moolenaar 
44887ba5a7efSBram Moolenaar 	if (IS_LL_STACK(qi))
4489ad52f96aSYegappan Lakshmanan 	{
4490ad52f96aSYegappan Lakshmanan 	    if (curwin->w_llist == qi)
4491ad52f96aSYegappan Lakshmanan 		win = curwin;
4492ad52f96aSYegappan Lakshmanan 	    else
4493ad52f96aSYegappan Lakshmanan 	    {
4494ad52f96aSYegappan Lakshmanan 		win = qf_find_win_with_loclist(qi);
4495ad52f96aSYegappan Lakshmanan 		if (win == NULL)
4496ad52f96aSYegappan Lakshmanan 		    return;
4497ad52f96aSYegappan Lakshmanan 	    }
4498ad52f96aSYegappan Lakshmanan 	    qf_winid = win->w_id;
4499ad52f96aSYegappan Lakshmanan 	}
4500864293abSBram Moolenaar 
4501864293abSBram Moolenaar 	if (old_last == NULL)
450200bf8cd2SBram Moolenaar 	    // set curwin/curbuf to buf and save a few things
4503071d4279SBram Moolenaar 	    aucmd_prepbuf(&aco, buf);
4504071d4279SBram Moolenaar 
4505d823fa91SBram Moolenaar 	qf_update_win_titlevar(qi);
4506c95e3263SBram Moolenaar 
45077ba5a7efSBram Moolenaar 	qf_fill_buffer(qf_get_curlist(qi), buf, old_last, qf_winid);
4508a8788f4dSBram Moolenaar 	++CHANGEDTICK(buf);
4509864293abSBram Moolenaar 
4510864293abSBram Moolenaar 	if (old_last == NULL)
4511864293abSBram Moolenaar 	{
4512864293abSBram Moolenaar 	    (void)qf_win_pos_update(qi, 0);
45136920c72dSBram Moolenaar 
451400bf8cd2SBram Moolenaar 	    // restore curwin/curbuf and a few other things
4515071d4279SBram Moolenaar 	    aucmd_restbuf(&aco);
4516864293abSBram Moolenaar 	}
4517071d4279SBram Moolenaar 
451800bf8cd2SBram Moolenaar 	// Only redraw when added lines are visible.  This avoids flickering
451900bf8cd2SBram Moolenaar 	// when the added lines are not visible.
4520864293abSBram Moolenaar 	if ((win = qf_find_win(qi)) != NULL && old_line_count < win->w_botline)
4521864293abSBram Moolenaar 	    redraw_buf_later(buf, NOT_VALID);
4522071d4279SBram Moolenaar     }
4523071d4279SBram Moolenaar }
4524071d4279SBram Moolenaar 
452581278efaSBram Moolenaar /*
45266053f2d2SBram Moolenaar  * Add an error line to the quickfix buffer.
4527071d4279SBram Moolenaar  */
45286053f2d2SBram Moolenaar     static int
qf_buf_add_line(buf_T * buf,linenr_T lnum,qfline_T * qfp,char_u * dirname,int first_bufline,char_u * qftf_str)4529858ba06dSBram Moolenaar qf_buf_add_line(
4530858ba06dSBram Moolenaar 	buf_T		*buf,		// quickfix window buffer
4531858ba06dSBram Moolenaar 	linenr_T	lnum,
4532858ba06dSBram Moolenaar 	qfline_T	*qfp,
45337ba5a7efSBram Moolenaar 	char_u		*dirname,
45348ec92c97SBram Moolenaar 	int		first_bufline,
453500e260bbSBram Moolenaar 	char_u		*qftf_str)
4536071d4279SBram Moolenaar {
4537071d4279SBram Moolenaar     int		len;
45386053f2d2SBram Moolenaar     buf_T	*errbuf;
4539071d4279SBram Moolenaar 
4540d43906d2SBram Moolenaar     // If the 'quickfixtextfunc' function returned an non-empty custom string
4541d43906d2SBram Moolenaar     // for this entry, then use it.
4542d43906d2SBram Moolenaar     if (qftf_str != NULL && *qftf_str != NUL)
454300e260bbSBram Moolenaar 	vim_strncpy(IObuff, qftf_str, IOSIZE - 1);
4544858ba06dSBram Moolenaar     else
4545858ba06dSBram Moolenaar     {
4546d76ce852SBram Moolenaar 	if (qfp->qf_module != NULL)
4547d76ce852SBram Moolenaar 	{
4548a106e6cdSBram Moolenaar 	    vim_strncpy(IObuff, qfp->qf_module, IOSIZE - 1);
4549d76ce852SBram Moolenaar 	    len = (int)STRLEN(IObuff);
4550d76ce852SBram Moolenaar 	}
4551d76ce852SBram Moolenaar 	else if (qfp->qf_fnum != 0
4552071d4279SBram Moolenaar 		&& (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
4553071d4279SBram Moolenaar 		&& errbuf->b_fname != NULL)
4554071d4279SBram Moolenaar 	{
455500bf8cd2SBram Moolenaar 	    if (qfp->qf_type == 1)	// :helpgrep
4556a106e6cdSBram Moolenaar 		vim_strncpy(IObuff, gettail(errbuf->b_fname), IOSIZE - 1);
4557071d4279SBram Moolenaar 	    else
4558a796d46fSBram Moolenaar 	    {
45598ec92c97SBram Moolenaar 		// Shorten the file name if not done already.
45608ec92c97SBram Moolenaar 		// For optimization, do this only for the first entry in a
45618ec92c97SBram Moolenaar 		// buffer.
45628ec92c97SBram Moolenaar 		if (first_bufline && (errbuf->b_sfname == NULL
45638ec92c97SBram Moolenaar 				|| mch_isFullName(errbuf->b_sfname)))
4564a796d46fSBram Moolenaar 		{
4565a796d46fSBram Moolenaar 		    if (*dirname == NUL)
4566a796d46fSBram Moolenaar 			mch_dirname(dirname, MAXPATHL);
4567a796d46fSBram Moolenaar 		    shorten_buf_fname(errbuf, dirname, FALSE);
4568a796d46fSBram Moolenaar 		}
4569a106e6cdSBram Moolenaar 		vim_strncpy(IObuff, errbuf->b_fname, IOSIZE - 1);
4570a796d46fSBram Moolenaar 	    }
4571071d4279SBram Moolenaar 	    len = (int)STRLEN(IObuff);
4572071d4279SBram Moolenaar 	}
4573071d4279SBram Moolenaar 	else
4574071d4279SBram Moolenaar 	    len = 0;
4575a106e6cdSBram Moolenaar 
4576a106e6cdSBram Moolenaar 	if (len < IOSIZE - 1)
4577071d4279SBram Moolenaar 	    IObuff[len++] = '|';
4578071d4279SBram Moolenaar 
4579071d4279SBram Moolenaar 	if (qfp->qf_lnum > 0)
4580071d4279SBram Moolenaar 	{
45816864efa5Sthinca 	    qf_range_text(qfp, IObuff + len, IOSIZE - len);
4582071d4279SBram Moolenaar 	    len += (int)STRLEN(IObuff + len);
4583071d4279SBram Moolenaar 
4584a106e6cdSBram Moolenaar 	    vim_snprintf((char *)IObuff + len, IOSIZE - len, "%s",
4585071d4279SBram Moolenaar 		    (char *)qf_types(qfp->qf_type, qfp->qf_nr));
4586071d4279SBram Moolenaar 	    len += (int)STRLEN(IObuff + len);
4587071d4279SBram Moolenaar 	}
458868b76a69SBram Moolenaar 	else if (qfp->qf_pattern != NULL)
458968b76a69SBram Moolenaar 	{
459068b76a69SBram Moolenaar 	    qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len);
459168b76a69SBram Moolenaar 	    len += (int)STRLEN(IObuff + len);
459268b76a69SBram Moolenaar 	}
4593a106e6cdSBram Moolenaar 	if (len < IOSIZE - 2)
4594a106e6cdSBram Moolenaar 	{
4595071d4279SBram Moolenaar 	    IObuff[len++] = '|';
4596071d4279SBram Moolenaar 	    IObuff[len++] = ' ';
4597a106e6cdSBram Moolenaar 	}
4598071d4279SBram Moolenaar 
459900bf8cd2SBram Moolenaar 	// Remove newlines and leading whitespace from the text.
460000bf8cd2SBram Moolenaar 	// For an unrecognized line keep the indent, the compiler may
460100bf8cd2SBram Moolenaar 	// mark a word with ^^^^.
4602071d4279SBram Moolenaar 	qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text,
4603071d4279SBram Moolenaar 		IObuff + len, IOSIZE - len);
4604858ba06dSBram Moolenaar     }
4605071d4279SBram Moolenaar 
4606864293abSBram Moolenaar     if (ml_append_buf(buf, lnum, IObuff,
4607864293abSBram Moolenaar 		(colnr_T)STRLEN(IObuff) + 1, FALSE) == FAIL)
46086053f2d2SBram Moolenaar 	return FAIL;
46096053f2d2SBram Moolenaar 
46106053f2d2SBram Moolenaar     return OK;
46116053f2d2SBram Moolenaar }
46126053f2d2SBram Moolenaar 
4613d43906d2SBram Moolenaar /*
4614d43906d2SBram Moolenaar  * Call the 'quickfixtextfunc' function to get the list of lines to display in
4615d43906d2SBram Moolenaar  * the quickfix window for the entries 'start_idx' to 'end_idx'.
4616d43906d2SBram Moolenaar  */
461700e260bbSBram Moolenaar     static list_T *
call_qftf_func(qf_list_T * qfl,int qf_winid,long start_idx,long end_idx)461800e260bbSBram Moolenaar call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long end_idx)
461900e260bbSBram Moolenaar {
4620d43906d2SBram Moolenaar     callback_T	*cb = &qftf_cb;
462100e260bbSBram Moolenaar     list_T	*qftf_list = NULL;
462200e260bbSBram Moolenaar 
462300e260bbSBram Moolenaar     // If 'quickfixtextfunc' is set, then use the user-supplied function to get
462400e260bbSBram Moolenaar     // the text to display. Use the local value of 'quickfixtextfunc' if it is
462500e260bbSBram Moolenaar     // set.
4626d43906d2SBram Moolenaar     if (qfl->qftf_cb.cb_name != NULL)
4627d43906d2SBram Moolenaar 	cb = &qfl->qftf_cb;
4628d43906d2SBram Moolenaar     if (cb != NULL && cb->cb_name != NULL)
462900e260bbSBram Moolenaar     {
463000e260bbSBram Moolenaar 	typval_T	args[1];
463100e260bbSBram Moolenaar 	dict_T		*d;
4632d43906d2SBram Moolenaar 	typval_T	rettv;
463300e260bbSBram Moolenaar 
463400e260bbSBram Moolenaar 	// create the dict argument
463500e260bbSBram Moolenaar 	if ((d = dict_alloc_lock(VAR_FIXED)) == NULL)
463600e260bbSBram Moolenaar 	    return NULL;
463700e260bbSBram Moolenaar 	dict_add_number(d, "quickfix", (long)IS_QF_LIST(qfl));
463800e260bbSBram Moolenaar 	dict_add_number(d, "winid", (long)qf_winid);
463900e260bbSBram Moolenaar 	dict_add_number(d, "id", (long)qfl->qf_id);
464000e260bbSBram Moolenaar 	dict_add_number(d, "start_idx", start_idx);
464100e260bbSBram Moolenaar 	dict_add_number(d, "end_idx", end_idx);
464200e260bbSBram Moolenaar 	++d->dv_refcount;
464300e260bbSBram Moolenaar 	args[0].v_type = VAR_DICT;
464400e260bbSBram Moolenaar 	args[0].vval.v_dict = d;
464500e260bbSBram Moolenaar 
4646d43906d2SBram Moolenaar 	qftf_list = NULL;
4647d43906d2SBram Moolenaar 	if (call_callback(cb, 0, &rettv, 1, args) != FAIL)
4648d43906d2SBram Moolenaar 	{
4649d43906d2SBram Moolenaar 	    if (rettv.v_type == VAR_LIST)
4650d43906d2SBram Moolenaar 	    {
4651d43906d2SBram Moolenaar 		qftf_list = rettv.vval.v_list;
4652d43906d2SBram Moolenaar 		qftf_list->lv_refcount++;
4653d43906d2SBram Moolenaar 	    }
4654d43906d2SBram Moolenaar 	    clear_tv(&rettv);
4655d43906d2SBram Moolenaar 	}
4656d43906d2SBram Moolenaar 	dict_unref(d);
465700e260bbSBram Moolenaar     }
465800e260bbSBram Moolenaar 
465900e260bbSBram Moolenaar     return qftf_list;
466000e260bbSBram Moolenaar }
466100e260bbSBram Moolenaar 
46626053f2d2SBram Moolenaar /*
46636053f2d2SBram Moolenaar  * Fill current buffer with quickfix errors, replacing any previous contents.
46646053f2d2SBram Moolenaar  * curbuf must be the quickfix buffer!
46656053f2d2SBram Moolenaar  * If "old_last" is not NULL append the items after this one.
46666053f2d2SBram Moolenaar  * When "old_last" is NULL then "buf" must equal "curbuf"!  Because
46676053f2d2SBram Moolenaar  * ml_delete() is used and autocommands will be triggered.
46686053f2d2SBram Moolenaar  */
46696053f2d2SBram Moolenaar     static void
qf_fill_buffer(qf_list_T * qfl,buf_T * buf,qfline_T * old_last,int qf_winid)46707ba5a7efSBram Moolenaar qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid)
46716053f2d2SBram Moolenaar {
46726053f2d2SBram Moolenaar     linenr_T	lnum;
46736053f2d2SBram Moolenaar     qfline_T	*qfp;
46746053f2d2SBram Moolenaar     int		old_KeyTyped = KeyTyped;
467500e260bbSBram Moolenaar     list_T	*qftf_list = NULL;
467600e260bbSBram Moolenaar     listitem_T	*qftf_li = NULL;
46776053f2d2SBram Moolenaar 
46786053f2d2SBram Moolenaar     if (old_last == NULL)
46796053f2d2SBram Moolenaar     {
46806053f2d2SBram Moolenaar 	if (buf != curbuf)
46816053f2d2SBram Moolenaar 	{
46826053f2d2SBram Moolenaar 	    internal_error("qf_fill_buffer()");
46836053f2d2SBram Moolenaar 	    return;
46846053f2d2SBram Moolenaar 	}
46856053f2d2SBram Moolenaar 
468600bf8cd2SBram Moolenaar 	// delete all existing lines
46876053f2d2SBram Moolenaar 	while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0)
4688ca70c07bSBram Moolenaar 	    (void)ml_delete((linenr_T)1);
46896053f2d2SBram Moolenaar     }
46906053f2d2SBram Moolenaar 
469100bf8cd2SBram Moolenaar     // Check if there is anything to display
46924aa47b28SBram Moolenaar     if (qfl != NULL)
46936053f2d2SBram Moolenaar     {
46946053f2d2SBram Moolenaar 	char_u		dirname[MAXPATHL];
4695d43906d2SBram Moolenaar 	int		invalid_val = FALSE;
46968ec92c97SBram Moolenaar 	int		prev_bufnr = -1;
46976053f2d2SBram Moolenaar 
46986053f2d2SBram Moolenaar 	*dirname = NUL;
46996053f2d2SBram Moolenaar 
470000bf8cd2SBram Moolenaar 	// Add one line for each error
47012ce77903SBram Moolenaar 	if (old_last == NULL)
47026053f2d2SBram Moolenaar 	{
4703108e7b42SBram Moolenaar 	    qfp = qfl->qf_start;
47046053f2d2SBram Moolenaar 	    lnum = 0;
47056053f2d2SBram Moolenaar 	}
47066053f2d2SBram Moolenaar 	else
47076053f2d2SBram Moolenaar 	{
47082ce77903SBram Moolenaar 	    if (old_last->qf_next != NULL)
47096053f2d2SBram Moolenaar 		qfp = old_last->qf_next;
47102ce77903SBram Moolenaar 	    else
47112ce77903SBram Moolenaar 		qfp = old_last;
47126053f2d2SBram Moolenaar 	    lnum = buf->b_ml.ml_line_count;
47136053f2d2SBram Moolenaar 	}
471400e260bbSBram Moolenaar 
471500e260bbSBram Moolenaar 	qftf_list = call_qftf_func(qfl, qf_winid, (long)(lnum + 1),
471600e260bbSBram Moolenaar 							(long)qfl->qf_count);
471700e260bbSBram Moolenaar 	if (qftf_list != NULL)
471800e260bbSBram Moolenaar 	    qftf_li = qftf_list->lv_first;
471900e260bbSBram Moolenaar 
4720108e7b42SBram Moolenaar 	while (lnum < qfl->qf_count)
47216053f2d2SBram Moolenaar 	{
472200e260bbSBram Moolenaar 	    char_u	*qftf_str = NULL;
472300e260bbSBram Moolenaar 
4724d43906d2SBram Moolenaar 	    // Use the text supplied by the user defined function (if any).
4725d43906d2SBram Moolenaar 	    // If the returned value is not string, then ignore the rest
4726d43906d2SBram Moolenaar 	    // of the returned values and use the default.
4727d43906d2SBram Moolenaar 	    if (qftf_li != NULL && !invalid_val)
4728d43906d2SBram Moolenaar 	    {
472900e260bbSBram Moolenaar 		qftf_str = tv_get_string_chk(&qftf_li->li_tv);
4730d43906d2SBram Moolenaar 		if (qftf_str == NULL)
4731d43906d2SBram Moolenaar 		    invalid_val = TRUE;
4732d43906d2SBram Moolenaar 	    }
473300e260bbSBram Moolenaar 
47348ec92c97SBram Moolenaar 	    if (qf_buf_add_line(buf, lnum, qfp, dirname,
47358ec92c97SBram Moolenaar 			prev_bufnr != qfp->qf_fnum, qftf_str) == FAIL)
4736071d4279SBram Moolenaar 		break;
47376053f2d2SBram Moolenaar 
47388ec92c97SBram Moolenaar 	    prev_bufnr = qfp->qf_fnum;
4739864293abSBram Moolenaar 	    ++lnum;
4740071d4279SBram Moolenaar 	    qfp = qfp->qf_next;
474183e6d7acSBram Moolenaar 	    if (qfp == NULL)
474283e6d7acSBram Moolenaar 		break;
474300e260bbSBram Moolenaar 
474400e260bbSBram Moolenaar 	    if (qftf_li != NULL)
474500e260bbSBram Moolenaar 		qftf_li = qftf_li->li_next;
4746071d4279SBram Moolenaar 	}
4747864293abSBram Moolenaar 
4748864293abSBram Moolenaar 	if (old_last == NULL)
474900bf8cd2SBram Moolenaar 	    // Delete the empty line which is now at the end
4750ca70c07bSBram Moolenaar 	    (void)ml_delete(lnum + 1);
4751071d4279SBram Moolenaar     }
4752071d4279SBram Moolenaar 
475300bf8cd2SBram Moolenaar     // correct cursor position
4754071d4279SBram Moolenaar     check_lnums(TRUE);
4755071d4279SBram Moolenaar 
4756864293abSBram Moolenaar     if (old_last == NULL)
4757864293abSBram Moolenaar     {
475800bf8cd2SBram Moolenaar 	// Set the 'filetype' to "qf" each time after filling the buffer.
475900bf8cd2SBram Moolenaar 	// This resembles reading a file into a buffer, it's more logical when
476000bf8cd2SBram Moolenaar 	// using autocommands.
47611814183bSBram Moolenaar 	++curbuf_lock;
4762071d4279SBram Moolenaar 	set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL);
4763071d4279SBram Moolenaar 	curbuf->b_p_ma = FALSE;
4764071d4279SBram Moolenaar 
476500bf8cd2SBram Moolenaar 	keep_filetype = TRUE;		// don't detect 'filetype'
4766071d4279SBram Moolenaar 	apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL,
4767071d4279SBram Moolenaar 							       FALSE, curbuf);
4768071d4279SBram Moolenaar 	apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL,
4769071d4279SBram Moolenaar 							       FALSE, curbuf);
477004c0f8a9SBram Moolenaar 	keep_filetype = FALSE;
47711814183bSBram Moolenaar 	--curbuf_lock;
4772f2bd8ef2SBram Moolenaar 
477300bf8cd2SBram Moolenaar 	// make sure it will be redrawn
4774071d4279SBram Moolenaar 	redraw_curbuf_later(NOT_VALID);
4775864293abSBram Moolenaar     }
4776071d4279SBram Moolenaar 
477700bf8cd2SBram Moolenaar     // Restore KeyTyped, setting 'filetype' may reset it.
4778071d4279SBram Moolenaar     KeyTyped = old_KeyTyped;
4779071d4279SBram Moolenaar }
4780071d4279SBram Moolenaar 
478118cebf44SBram Moolenaar /*
478218cebf44SBram Moolenaar  * For every change made to the quickfix list, update the changed tick.
478318cebf44SBram Moolenaar  */
4784b254af31SBram Moolenaar     static void
qf_list_changed(qf_list_T * qfl)4785108e7b42SBram Moolenaar qf_list_changed(qf_list_T *qfl)
4786b254af31SBram Moolenaar {
4787108e7b42SBram Moolenaar     qfl->qf_changedtick++;
4788b254af31SBram Moolenaar }
4789b254af31SBram Moolenaar 
4790071d4279SBram Moolenaar /*
4791531b9a3aSBram Moolenaar  * Return the quickfix/location list number with the given identifier.
4792531b9a3aSBram Moolenaar  * Returns -1 if list is not found.
4793531b9a3aSBram Moolenaar  */
4794531b9a3aSBram Moolenaar     static int
qf_id2nr(qf_info_T * qi,int_u qfid)4795531b9a3aSBram Moolenaar qf_id2nr(qf_info_T *qi, int_u qfid)
4796531b9a3aSBram Moolenaar {
4797531b9a3aSBram Moolenaar     int		qf_idx;
4798531b9a3aSBram Moolenaar 
4799531b9a3aSBram Moolenaar     for (qf_idx = 0; qf_idx < qi->qf_listcount; qf_idx++)
4800531b9a3aSBram Moolenaar 	if (qi->qf_lists[qf_idx].qf_id == qfid)
4801531b9a3aSBram Moolenaar 	    return qf_idx;
4802531b9a3aSBram Moolenaar     return INVALID_QFIDX;
4803531b9a3aSBram Moolenaar }
4804531b9a3aSBram Moolenaar 
4805531b9a3aSBram Moolenaar /*
480638efd1d1SBram Moolenaar  * If the current list is not "save_qfid" and we can find the list with that ID
480738efd1d1SBram Moolenaar  * then make it the current list.
480838efd1d1SBram Moolenaar  * This is used when autocommands may have changed the current list.
480990f1e2b7SBram Moolenaar  * Returns OK if successfully restored the list. Returns FAIL if the list with
481090f1e2b7SBram Moolenaar  * the specified identifier (save_qfid) is not found in the stack.
481138efd1d1SBram Moolenaar  */
481290f1e2b7SBram Moolenaar     static int
qf_restore_list(qf_info_T * qi,int_u save_qfid)481338efd1d1SBram Moolenaar qf_restore_list(qf_info_T *qi, int_u save_qfid)
481438efd1d1SBram Moolenaar {
481538efd1d1SBram Moolenaar     int curlist;
481638efd1d1SBram Moolenaar 
48174aa47b28SBram Moolenaar     if (qf_get_curlist(qi)->qf_id != save_qfid)
481838efd1d1SBram Moolenaar     {
481938efd1d1SBram Moolenaar 	curlist = qf_id2nr(qi, save_qfid);
482090f1e2b7SBram Moolenaar 	if (curlist < 0)
482190f1e2b7SBram Moolenaar 	    // list is not present
482290f1e2b7SBram Moolenaar 	    return FAIL;
482338efd1d1SBram Moolenaar 	qi->qf_curlist = curlist;
482438efd1d1SBram Moolenaar     }
482590f1e2b7SBram Moolenaar     return OK;
482638efd1d1SBram Moolenaar }
482738efd1d1SBram Moolenaar 
482838efd1d1SBram Moolenaar /*
48298d8a65e3SBram Moolenaar  * Jump to the first entry if there is one.
48308d8a65e3SBram Moolenaar  */
48318d8a65e3SBram Moolenaar     static void
qf_jump_first(qf_info_T * qi,int_u save_qfid,int forceit)48328d8a65e3SBram Moolenaar qf_jump_first(qf_info_T *qi, int_u save_qfid, int forceit)
48338d8a65e3SBram Moolenaar {
483490f1e2b7SBram Moolenaar     if (qf_restore_list(qi, save_qfid) == FAIL)
483590f1e2b7SBram Moolenaar 	return;
48368d8a65e3SBram Moolenaar 
483790f1e2b7SBram Moolenaar     // Autocommands might have cleared the list, check for that.
48380398e00aSBram Moolenaar     if (!qf_list_empty(qf_get_curlist(qi)))
48398d8a65e3SBram Moolenaar 	qf_jump(qi, 0, 0, forceit);
48408d8a65e3SBram Moolenaar }
48418d8a65e3SBram Moolenaar 
48428d8a65e3SBram Moolenaar /*
484386b68359SBram Moolenaar  * Return TRUE when using ":vimgrep" for ":grep".
484486b68359SBram Moolenaar  */
484586b68359SBram Moolenaar     int
grep_internal(cmdidx_T cmdidx)484605540976SBram Moolenaar grep_internal(cmdidx_T cmdidx)
484786b68359SBram Moolenaar {
4848754b5608SBram Moolenaar     return ((cmdidx == CMD_grep
4849754b5608SBram Moolenaar 		|| cmdidx == CMD_lgrep
4850754b5608SBram Moolenaar 		|| cmdidx == CMD_grepadd
4851754b5608SBram Moolenaar 		|| cmdidx == CMD_lgrepadd)
485286b68359SBram Moolenaar 	    && STRCMP("internal",
485386b68359SBram Moolenaar 			*curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0);
485486b68359SBram Moolenaar }
485586b68359SBram Moolenaar 
485686b68359SBram Moolenaar /*
4857b434ae2aSBram Moolenaar  * Return the make/grep autocmd name.
4858071d4279SBram Moolenaar  */
4859b434ae2aSBram Moolenaar     static char_u *
make_get_auname(cmdidx_T cmdidx)4860b434ae2aSBram Moolenaar make_get_auname(cmdidx_T cmdidx)
4861071d4279SBram Moolenaar {
4862b434ae2aSBram Moolenaar     switch (cmdidx)
4863d88e02deSBram Moolenaar     {
4864b434ae2aSBram Moolenaar 	case CMD_make:	    return (char_u *)"make";
4865b434ae2aSBram Moolenaar 	case CMD_lmake:	    return (char_u *)"lmake";
4866b434ae2aSBram Moolenaar 	case CMD_grep:	    return (char_u *)"grep";
4867b434ae2aSBram Moolenaar 	case CMD_lgrep:	    return (char_u *)"lgrep";
4868b434ae2aSBram Moolenaar 	case CMD_grepadd:   return (char_u *)"grepadd";
4869b434ae2aSBram Moolenaar 	case CMD_lgrepadd:  return (char_u *)"lgrepadd";
4870b434ae2aSBram Moolenaar 	default: return NULL;
4871d88e02deSBram Moolenaar     }
4872071d4279SBram Moolenaar }
4873071d4279SBram Moolenaar 
4874071d4279SBram Moolenaar /*
4875071d4279SBram Moolenaar  * Return the name for the errorfile, in allocated memory.
4876071d4279SBram Moolenaar  * Find a new unique name when 'makeef' contains "##".
4877071d4279SBram Moolenaar  * Returns NULL for error.
4878071d4279SBram Moolenaar  */
4879071d4279SBram Moolenaar     static char_u *
get_mef_name(void)488005540976SBram Moolenaar get_mef_name(void)
4881071d4279SBram Moolenaar {
4882071d4279SBram Moolenaar     char_u	*p;
4883071d4279SBram Moolenaar     char_u	*name;
4884071d4279SBram Moolenaar     static int	start = -1;
4885071d4279SBram Moolenaar     static int	off = 0;
4886071d4279SBram Moolenaar #ifdef HAVE_LSTAT
48878767f52fSBram Moolenaar     stat_T	sb;
4888071d4279SBram Moolenaar #endif
4889071d4279SBram Moolenaar 
4890071d4279SBram Moolenaar     if (*p_mef == NUL)
4891071d4279SBram Moolenaar     {
4892e5c421cfSBram Moolenaar 	name = vim_tempname('e', FALSE);
4893071d4279SBram Moolenaar 	if (name == NULL)
4894f9e3e09fSBram Moolenaar 	    emsg(_(e_notmp));
4895071d4279SBram Moolenaar 	return name;
4896071d4279SBram Moolenaar     }
4897071d4279SBram Moolenaar 
4898071d4279SBram Moolenaar     for (p = p_mef; *p; ++p)
4899071d4279SBram Moolenaar 	if (p[0] == '#' && p[1] == '#')
4900071d4279SBram Moolenaar 	    break;
4901071d4279SBram Moolenaar 
4902071d4279SBram Moolenaar     if (*p == NUL)
4903071d4279SBram Moolenaar 	return vim_strsave(p_mef);
4904071d4279SBram Moolenaar 
4905b434ae2aSBram Moolenaar     // Keep trying until the name doesn't exist yet.
4906071d4279SBram Moolenaar     for (;;)
4907071d4279SBram Moolenaar     {
4908071d4279SBram Moolenaar 	if (start == -1)
4909071d4279SBram Moolenaar 	    start = mch_get_pid();
4910071d4279SBram Moolenaar 	else
4911071d4279SBram Moolenaar 	    off += 19;
4912071d4279SBram Moolenaar 
4913964b3746SBram Moolenaar 	name = alloc(STRLEN(p_mef) + 30);
4914071d4279SBram Moolenaar 	if (name == NULL)
4915071d4279SBram Moolenaar 	    break;
4916071d4279SBram Moolenaar 	STRCPY(name, p_mef);
4917071d4279SBram Moolenaar 	sprintf((char *)name + (p - p_mef), "%d%d", start, off);
4918071d4279SBram Moolenaar 	STRCAT(name, p + 2);
4919071d4279SBram Moolenaar 	if (mch_getperm(name) < 0
4920071d4279SBram Moolenaar #ifdef HAVE_LSTAT
4921b434ae2aSBram Moolenaar 		    // Don't accept a symbolic link, it's a security risk.
4922071d4279SBram Moolenaar 		    && mch_lstat((char *)name, &sb) < 0
4923071d4279SBram Moolenaar #endif
4924071d4279SBram Moolenaar 		)
4925071d4279SBram Moolenaar 	    break;
4926071d4279SBram Moolenaar 	vim_free(name);
4927071d4279SBram Moolenaar     }
4928071d4279SBram Moolenaar     return name;
4929071d4279SBram Moolenaar }
4930071d4279SBram Moolenaar 
4931071d4279SBram Moolenaar /*
4932b434ae2aSBram Moolenaar  * Form the complete command line to invoke 'make'/'grep'. Quote the command
4933b434ae2aSBram Moolenaar  * using 'shellquote' and append 'shellpipe'. Echo the fully formed command.
4934b434ae2aSBram Moolenaar  */
4935b434ae2aSBram Moolenaar     static char_u *
make_get_fullcmd(char_u * makecmd,char_u * fname)4936b434ae2aSBram Moolenaar make_get_fullcmd(char_u *makecmd, char_u *fname)
4937b434ae2aSBram Moolenaar {
4938b434ae2aSBram Moolenaar     char_u	*cmd;
4939b434ae2aSBram Moolenaar     unsigned	len;
4940b434ae2aSBram Moolenaar 
4941b434ae2aSBram Moolenaar     len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(makecmd) + 1;
4942b434ae2aSBram Moolenaar     if (*p_sp != NUL)
4943b434ae2aSBram Moolenaar 	len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(fname) + 3;
4944b434ae2aSBram Moolenaar     cmd = alloc(len);
4945b434ae2aSBram Moolenaar     if (cmd == NULL)
4946b434ae2aSBram Moolenaar 	return NULL;
4947b434ae2aSBram Moolenaar     sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)makecmd,
4948b434ae2aSBram Moolenaar 							       (char *)p_shq);
4949b434ae2aSBram Moolenaar 
4950b434ae2aSBram Moolenaar     // If 'shellpipe' empty: don't redirect to 'errorfile'.
4951b434ae2aSBram Moolenaar     if (*p_sp != NUL)
4952b434ae2aSBram Moolenaar 	append_redir(cmd, len, p_sp, fname);
4953b434ae2aSBram Moolenaar 
4954b434ae2aSBram Moolenaar     // Display the fully formed command.  Output a newline if there's something
4955b434ae2aSBram Moolenaar     // else than the :make command that was typed (in which case the cursor is
4956b434ae2aSBram Moolenaar     // in column 0).
4957b434ae2aSBram Moolenaar     if (msg_col == 0)
4958b434ae2aSBram Moolenaar 	msg_didout = FALSE;
4959b434ae2aSBram Moolenaar     msg_start();
496032526b3cSBram Moolenaar     msg_puts(":!");
4961b434ae2aSBram Moolenaar     msg_outtrans(cmd);		// show what we are doing
4962b434ae2aSBram Moolenaar 
4963b434ae2aSBram Moolenaar     return cmd;
4964b434ae2aSBram Moolenaar }
4965b434ae2aSBram Moolenaar 
4966b434ae2aSBram Moolenaar /*
4967b434ae2aSBram Moolenaar  * Used for ":make", ":lmake", ":grep", ":lgrep", ":grepadd", and ":lgrepadd"
4968b434ae2aSBram Moolenaar  */
4969b434ae2aSBram Moolenaar     void
ex_make(exarg_T * eap)4970b434ae2aSBram Moolenaar ex_make(exarg_T *eap)
4971b434ae2aSBram Moolenaar {
4972b434ae2aSBram Moolenaar     char_u	*fname;
4973b434ae2aSBram Moolenaar     char_u	*cmd;
4974b434ae2aSBram Moolenaar     char_u	*enc = NULL;
4975b434ae2aSBram Moolenaar     win_T	*wp = NULL;
4976b434ae2aSBram Moolenaar     qf_info_T	*qi = &ql_info;
4977b434ae2aSBram Moolenaar     int		res;
4978b434ae2aSBram Moolenaar     char_u	*au_name = NULL;
4979b434ae2aSBram Moolenaar     int_u	save_qfid;
4980b434ae2aSBram Moolenaar 
4981b434ae2aSBram Moolenaar     // Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal".
4982b434ae2aSBram Moolenaar     if (grep_internal(eap->cmdidx))
4983b434ae2aSBram Moolenaar     {
4984b434ae2aSBram Moolenaar 	ex_vimgrep(eap);
4985b434ae2aSBram Moolenaar 	return;
4986b434ae2aSBram Moolenaar     }
4987b434ae2aSBram Moolenaar 
4988b434ae2aSBram Moolenaar     au_name = make_get_auname(eap->cmdidx);
4989b434ae2aSBram Moolenaar     if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
4990b434ae2aSBram Moolenaar 					       curbuf->b_fname, TRUE, curbuf))
4991b434ae2aSBram Moolenaar     {
4992b434ae2aSBram Moolenaar #ifdef FEAT_EVAL
4993b434ae2aSBram Moolenaar 	if (aborting())
4994b434ae2aSBram Moolenaar 	    return;
4995b434ae2aSBram Moolenaar #endif
4996b434ae2aSBram Moolenaar     }
4997b434ae2aSBram Moolenaar     enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc;
4998b434ae2aSBram Moolenaar 
4999b434ae2aSBram Moolenaar     if (is_loclist_cmd(eap->cmdidx))
5000b434ae2aSBram Moolenaar 	wp = curwin;
5001b434ae2aSBram Moolenaar 
5002b434ae2aSBram Moolenaar     autowrite_all();
5003b434ae2aSBram Moolenaar     fname = get_mef_name();
5004b434ae2aSBram Moolenaar     if (fname == NULL)
5005b434ae2aSBram Moolenaar 	return;
5006b434ae2aSBram Moolenaar     mch_remove(fname);	    // in case it's not unique
5007b434ae2aSBram Moolenaar 
5008b434ae2aSBram Moolenaar     cmd = make_get_fullcmd(eap->arg, fname);
5009b434ae2aSBram Moolenaar     if (cmd == NULL)
5010b434ae2aSBram Moolenaar 	return;
5011b434ae2aSBram Moolenaar 
5012b434ae2aSBram Moolenaar     // let the shell know if we are redirecting output or not
5013b434ae2aSBram Moolenaar     do_shell(cmd, *p_sp != NUL ? SHELL_DOOUT : 0);
5014b434ae2aSBram Moolenaar 
5015b434ae2aSBram Moolenaar #ifdef AMIGA
5016b434ae2aSBram Moolenaar     out_flush();
5017b434ae2aSBram Moolenaar 		// read window status report and redraw before message
5018b434ae2aSBram Moolenaar     (void)char_avail();
5019b434ae2aSBram Moolenaar #endif
5020b434ae2aSBram Moolenaar 
50219f84ded3SBram Moolenaar     incr_quickfix_busy();
50229f84ded3SBram Moolenaar 
5023b434ae2aSBram Moolenaar     res = qf_init(wp, fname, (eap->cmdidx != CMD_make
5024b434ae2aSBram Moolenaar 			    && eap->cmdidx != CMD_lmake) ? p_gefm : p_efm,
5025b434ae2aSBram Moolenaar 					   (eap->cmdidx != CMD_grepadd
5026b434ae2aSBram Moolenaar 					    && eap->cmdidx != CMD_lgrepadd),
5027b434ae2aSBram Moolenaar 					   qf_cmdtitle(*eap->cmdlinep), enc);
5028b434ae2aSBram Moolenaar     if (wp != NULL)
5029b434ae2aSBram Moolenaar     {
5030b434ae2aSBram Moolenaar 	qi = GET_LOC_LIST(wp);
5031b434ae2aSBram Moolenaar 	if (qi == NULL)
5032b434ae2aSBram Moolenaar 	    goto cleanup;
5033b434ae2aSBram Moolenaar     }
5034b434ae2aSBram Moolenaar     if (res >= 0)
50354aa47b28SBram Moolenaar 	qf_list_changed(qf_get_curlist(qi));
5036b434ae2aSBram Moolenaar 
5037b434ae2aSBram Moolenaar     // Remember the current quickfix list identifier, so that we can
5038b434ae2aSBram Moolenaar     // check for autocommands changing the current quickfix list.
50394aa47b28SBram Moolenaar     save_qfid = qf_get_curlist(qi)->qf_id;
5040b434ae2aSBram Moolenaar     if (au_name != NULL)
5041b434ae2aSBram Moolenaar 	apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
5042b434ae2aSBram Moolenaar 					       curbuf->b_fname, TRUE, curbuf);
5043b434ae2aSBram Moolenaar     if (res > 0 && !eap->forceit && qflist_valid(wp, save_qfid))
5044b434ae2aSBram Moolenaar 	// display the first error
5045b434ae2aSBram Moolenaar 	qf_jump_first(qi, save_qfid, FALSE);
5046b434ae2aSBram Moolenaar 
5047b434ae2aSBram Moolenaar cleanup:
50489f84ded3SBram Moolenaar     decr_quickfix_busy();
5049b434ae2aSBram Moolenaar     mch_remove(fname);
5050b434ae2aSBram Moolenaar     vim_free(fname);
5051b434ae2aSBram Moolenaar     vim_free(cmd);
5052b434ae2aSBram Moolenaar }
5053b434ae2aSBram Moolenaar 
5054b434ae2aSBram Moolenaar /*
505525190db2SBram Moolenaar  * Returns the number of entries in the current quickfix/location list.
5056aa23b379SBram Moolenaar  */
5057aa23b379SBram Moolenaar     int
qf_get_size(exarg_T * eap)505805540976SBram Moolenaar qf_get_size(exarg_T *eap)
5059aa23b379SBram Moolenaar {
506087f59b09SBram Moolenaar     qf_info_T	*qi;
506125190db2SBram Moolenaar 
506225190db2SBram Moolenaar     if ((qi = qf_cmd_get_stack(eap, FALSE)) == NULL)
506325190db2SBram Moolenaar 	return 0;
506425190db2SBram Moolenaar     return qf_get_curlist(qi)->qf_count;
506525190db2SBram Moolenaar }
506625190db2SBram Moolenaar 
506725190db2SBram Moolenaar /*
506825190db2SBram Moolenaar  * Returns the number of valid entries in the current quickfix/location list.
506925190db2SBram Moolenaar  */
507025190db2SBram Moolenaar     int
qf_get_valid_size(exarg_T * eap)507125190db2SBram Moolenaar qf_get_valid_size(exarg_T *eap)
507225190db2SBram Moolenaar {
507325190db2SBram Moolenaar     qf_info_T	*qi;
5074108e7b42SBram Moolenaar     qf_list_T	*qfl;
5075aa23b379SBram Moolenaar     qfline_T	*qfp;
5076aa23b379SBram Moolenaar     int		i, sz = 0;
5077aa23b379SBram Moolenaar     int		prev_fnum = 0;
5078aa23b379SBram Moolenaar 
507987f59b09SBram Moolenaar     if ((qi = qf_cmd_get_stack(eap, FALSE)) == NULL)
5080aa23b379SBram Moolenaar 	return 0;
5081aa23b379SBram Moolenaar 
50824aa47b28SBram Moolenaar     qfl = qf_get_curlist(qi);
5083a16123a6SBram Moolenaar     FOR_ALL_QFL_ITEMS(qfl, qfp, i)
5084aa23b379SBram Moolenaar     {
5085aa23b379SBram Moolenaar 	if (qfp->qf_valid)
5086aa23b379SBram Moolenaar 	{
5087aa23b379SBram Moolenaar 	    if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo)
508800bf8cd2SBram Moolenaar 		sz++;	// Count all valid entries
5089aa23b379SBram Moolenaar 	    else if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)
5090aa23b379SBram Moolenaar 	    {
509100bf8cd2SBram Moolenaar 		// Count the number of files
5092aa23b379SBram Moolenaar 		sz++;
5093aa23b379SBram Moolenaar 		prev_fnum = qfp->qf_fnum;
5094aa23b379SBram Moolenaar 	    }
5095aa23b379SBram Moolenaar 	}
5096aa23b379SBram Moolenaar     }
5097aa23b379SBram Moolenaar 
5098aa23b379SBram Moolenaar     return sz;
5099aa23b379SBram Moolenaar }
5100aa23b379SBram Moolenaar 
5101aa23b379SBram Moolenaar /*
5102aa23b379SBram Moolenaar  * Returns the current index of the quickfix/location list.
5103aa23b379SBram Moolenaar  * Returns 0 if there is an error.
5104aa23b379SBram Moolenaar  */
5105aa23b379SBram Moolenaar     int
qf_get_cur_idx(exarg_T * eap)510605540976SBram Moolenaar qf_get_cur_idx(exarg_T *eap)
5107aa23b379SBram Moolenaar {
510887f59b09SBram Moolenaar     qf_info_T	*qi;
5109aa23b379SBram Moolenaar 
511087f59b09SBram Moolenaar     if ((qi = qf_cmd_get_stack(eap, FALSE)) == NULL)
5111aa23b379SBram Moolenaar 	return 0;
5112aa23b379SBram Moolenaar 
51134aa47b28SBram Moolenaar     return qf_get_curlist(qi)->qf_index;
5114aa23b379SBram Moolenaar }
5115aa23b379SBram Moolenaar 
5116aa23b379SBram Moolenaar /*
5117aa23b379SBram Moolenaar  * Returns the current index in the quickfix/location list (counting only valid
5118aa23b379SBram Moolenaar  * entries). If no valid entries are in the list, then returns 1.
5119aa23b379SBram Moolenaar  */
5120aa23b379SBram Moolenaar     int
qf_get_cur_valid_idx(exarg_T * eap)512105540976SBram Moolenaar qf_get_cur_valid_idx(exarg_T *eap)
5122aa23b379SBram Moolenaar {
512387f59b09SBram Moolenaar     qf_info_T	*qi;
5124aa23b379SBram Moolenaar     qf_list_T	*qfl;
5125aa23b379SBram Moolenaar     qfline_T	*qfp;
5126aa23b379SBram Moolenaar     int		i, eidx = 0;
5127aa23b379SBram Moolenaar     int		prev_fnum = 0;
5128aa23b379SBram Moolenaar 
512987f59b09SBram Moolenaar     if ((qi = qf_cmd_get_stack(eap, FALSE)) == NULL)
5130aa23b379SBram Moolenaar 	return 1;
5131aa23b379SBram Moolenaar 
51324aa47b28SBram Moolenaar     qfl = qf_get_curlist(qi);
5133aa23b379SBram Moolenaar     qfp = qfl->qf_start;
5134aa23b379SBram Moolenaar 
513500bf8cd2SBram Moolenaar     // check if the list has valid errors
51363ff33114SBram Moolenaar     if (!qf_list_has_valid_entries(qfl))
5137aa23b379SBram Moolenaar 	return 1;
5138aa23b379SBram Moolenaar 
5139aa23b379SBram Moolenaar     for (i = 1; i <= qfl->qf_index && qfp!= NULL; i++, qfp = qfp->qf_next)
5140aa23b379SBram Moolenaar     {
5141aa23b379SBram Moolenaar 	if (qfp->qf_valid)
5142aa23b379SBram Moolenaar 	{
5143aa23b379SBram Moolenaar 	    if (eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
5144aa23b379SBram Moolenaar 	    {
5145aa23b379SBram Moolenaar 		if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)
5146aa23b379SBram Moolenaar 		{
514700bf8cd2SBram Moolenaar 		    // Count the number of files
5148aa23b379SBram Moolenaar 		    eidx++;
5149aa23b379SBram Moolenaar 		    prev_fnum = qfp->qf_fnum;
5150aa23b379SBram Moolenaar 		}
5151aa23b379SBram Moolenaar 	    }
5152aa23b379SBram Moolenaar 	    else
5153aa23b379SBram Moolenaar 		eidx++;
5154aa23b379SBram Moolenaar 	}
5155aa23b379SBram Moolenaar     }
5156aa23b379SBram Moolenaar 
5157aa23b379SBram Moolenaar     return eidx ? eidx : 1;
5158aa23b379SBram Moolenaar }
5159aa23b379SBram Moolenaar 
5160aa23b379SBram Moolenaar /*
5161aa23b379SBram Moolenaar  * Get the 'n'th valid error entry in the quickfix or location list.
5162aa23b379SBram Moolenaar  * Used by :cdo, :ldo, :cfdo and :lfdo commands.
5163aa23b379SBram Moolenaar  * For :cdo and :ldo returns the 'n'th valid error entry.
5164aa23b379SBram Moolenaar  * For :cfdo and :lfdo returns the 'n'th valid file entry.
5165aa23b379SBram Moolenaar  */
5166aa23b379SBram Moolenaar     static int
qf_get_nth_valid_entry(qf_list_T * qfl,int n,int fdo)5167fe15b7dfSBram Moolenaar qf_get_nth_valid_entry(qf_list_T *qfl, int n, int fdo)
5168aa23b379SBram Moolenaar {
516995946f12SBram Moolenaar     qfline_T	*qfp;
5170aa23b379SBram Moolenaar     int		i, eidx;
5171aa23b379SBram Moolenaar     int		prev_fnum = 0;
5172aa23b379SBram Moolenaar 
517300bf8cd2SBram Moolenaar     // check if the list has valid errors
51743ff33114SBram Moolenaar     if (!qf_list_has_valid_entries(qfl))
5175aa23b379SBram Moolenaar 	return 1;
5176aa23b379SBram Moolenaar 
517795946f12SBram Moolenaar     eidx = 0;
517895946f12SBram Moolenaar     FOR_ALL_QFL_ITEMS(qfl, qfp, i)
5179aa23b379SBram Moolenaar     {
5180aa23b379SBram Moolenaar 	if (qfp->qf_valid)
5181aa23b379SBram Moolenaar 	{
5182aa23b379SBram Moolenaar 	    if (fdo)
5183aa23b379SBram Moolenaar 	    {
5184aa23b379SBram Moolenaar 		if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)
5185aa23b379SBram Moolenaar 		{
518600bf8cd2SBram Moolenaar 		    // Count the number of files
5187aa23b379SBram Moolenaar 		    eidx++;
5188aa23b379SBram Moolenaar 		    prev_fnum = qfp->qf_fnum;
5189aa23b379SBram Moolenaar 		}
5190aa23b379SBram Moolenaar 	    }
5191aa23b379SBram Moolenaar 	    else
5192aa23b379SBram Moolenaar 		eidx++;
5193aa23b379SBram Moolenaar 	}
5194aa23b379SBram Moolenaar 
5195aa23b379SBram Moolenaar 	if (eidx == n)
5196aa23b379SBram Moolenaar 	    break;
5197aa23b379SBram Moolenaar     }
5198aa23b379SBram Moolenaar 
5199aa23b379SBram Moolenaar     if (i <= qfl->qf_count)
5200aa23b379SBram Moolenaar 	return i;
5201aa23b379SBram Moolenaar     else
5202aa23b379SBram Moolenaar 	return 1;
5203aa23b379SBram Moolenaar }
5204aa23b379SBram Moolenaar 
5205aa23b379SBram Moolenaar /*
5206071d4279SBram Moolenaar  * ":cc", ":crewind", ":cfirst" and ":clast".
5207d12f5c17SBram Moolenaar  * ":ll", ":lrewind", ":lfirst" and ":llast".
5208aa23b379SBram Moolenaar  * ":cdo", ":ldo", ":cfdo" and ":lfdo"
5209071d4279SBram Moolenaar  */
5210071d4279SBram Moolenaar     void
ex_cc(exarg_T * eap)521105540976SBram Moolenaar ex_cc(exarg_T *eap)
5212071d4279SBram Moolenaar {
521387f59b09SBram Moolenaar     qf_info_T	*qi;
5214aa23b379SBram Moolenaar     int		errornr;
5215d12f5c17SBram Moolenaar 
521687f59b09SBram Moolenaar     if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
5217d12f5c17SBram Moolenaar 	return;
5218d12f5c17SBram Moolenaar 
5219aa23b379SBram Moolenaar     if (eap->addr_count > 0)
5220aa23b379SBram Moolenaar 	errornr = (int)eap->line2;
5221aa23b379SBram Moolenaar     else
5222aa23b379SBram Moolenaar     {
522339665959SBram Moolenaar 	switch (eap->cmdidx)
522439665959SBram Moolenaar 	{
522539665959SBram Moolenaar 	    case CMD_cc: case CMD_ll:
5226aa23b379SBram Moolenaar 		errornr = 0;
522739665959SBram Moolenaar 		break;
522839665959SBram Moolenaar 	    case CMD_crewind: case CMD_lrewind: case CMD_cfirst:
522939665959SBram Moolenaar 	    case CMD_lfirst:
5230aa23b379SBram Moolenaar 		errornr = 1;
523139665959SBram Moolenaar 		break;
523239665959SBram Moolenaar 	    default:
5233aa23b379SBram Moolenaar 		errornr = 32767;
5234aa23b379SBram Moolenaar 	}
523539665959SBram Moolenaar     }
5236aa23b379SBram Moolenaar 
523700bf8cd2SBram Moolenaar     // For cdo and ldo commands, jump to the nth valid error.
523800bf8cd2SBram Moolenaar     // For cfdo and lfdo commands, jump to the nth valid file entry.
523955b69264SBram Moolenaar     if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
524055b69264SBram Moolenaar 	    || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
52414aa47b28SBram Moolenaar 	errornr = qf_get_nth_valid_entry(qf_get_curlist(qi),
5242aa23b379SBram Moolenaar 		eap->addr_count > 0 ? (int)eap->line1 : 1,
5243aa23b379SBram Moolenaar 		eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo);
5244aa23b379SBram Moolenaar 
5245aa23b379SBram Moolenaar     qf_jump(qi, 0, errornr, eap->forceit);
5246071d4279SBram Moolenaar }
5247071d4279SBram Moolenaar 
5248071d4279SBram Moolenaar /*
5249071d4279SBram Moolenaar  * ":cnext", ":cnfile", ":cNext" and ":cprevious".
5250d12f5c17SBram Moolenaar  * ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile".
5251aa23b379SBram Moolenaar  * Also, used by ":cdo", ":ldo", ":cfdo" and ":lfdo" commands.
5252071d4279SBram Moolenaar  */
5253071d4279SBram Moolenaar     void
ex_cnext(exarg_T * eap)525405540976SBram Moolenaar ex_cnext(exarg_T *eap)
5255071d4279SBram Moolenaar {
525687f59b09SBram Moolenaar     qf_info_T	*qi;
5257aa23b379SBram Moolenaar     int		errornr;
525839665959SBram Moolenaar     int		dir;
5259d12f5c17SBram Moolenaar 
526087f59b09SBram Moolenaar     if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
5261d12f5c17SBram Moolenaar 	return;
5262d12f5c17SBram Moolenaar 
526355b69264SBram Moolenaar     if (eap->addr_count > 0
526455b69264SBram Moolenaar 	    && (eap->cmdidx != CMD_cdo && eap->cmdidx != CMD_ldo
526555b69264SBram Moolenaar 		&& eap->cmdidx != CMD_cfdo && eap->cmdidx != CMD_lfdo))
5266aa23b379SBram Moolenaar 	errornr = (int)eap->line2;
5267aa23b379SBram Moolenaar     else
5268aa23b379SBram Moolenaar 	errornr = 1;
5269aa23b379SBram Moolenaar 
527039665959SBram Moolenaar     // Depending on the command jump to either next or previous entry/file.
527139665959SBram Moolenaar     switch (eap->cmdidx)
527239665959SBram Moolenaar     {
527339665959SBram Moolenaar 	case CMD_cnext: case CMD_lnext: case CMD_cdo: case CMD_ldo:
527439665959SBram Moolenaar 	    dir = FORWARD;
527539665959SBram Moolenaar 	    break;
527639665959SBram Moolenaar 	case CMD_cprevious: case CMD_lprevious: case CMD_cNext:
527739665959SBram Moolenaar 	case CMD_lNext:
527839665959SBram Moolenaar 	    dir = BACKWARD;
527939665959SBram Moolenaar 	    break;
528039665959SBram Moolenaar 	case CMD_cnfile: case CMD_lnfile: case CMD_cfdo: case CMD_lfdo:
528139665959SBram Moolenaar 	    dir = FORWARD_FILE;
528239665959SBram Moolenaar 	    break;
528339665959SBram Moolenaar 	case CMD_cpfile: case CMD_lpfile: case CMD_cNfile: case CMD_lNfile:
528439665959SBram Moolenaar 	    dir = BACKWARD_FILE;
528539665959SBram Moolenaar 	    break;
528639665959SBram Moolenaar 	default:
528739665959SBram Moolenaar 	    dir = FORWARD;
528839665959SBram Moolenaar 	    break;
528939665959SBram Moolenaar     }
529039665959SBram Moolenaar 
529139665959SBram Moolenaar     qf_jump(qi, dir, errornr, eap->forceit);
5292071d4279SBram Moolenaar }
5293071d4279SBram Moolenaar 
5294071d4279SBram Moolenaar /*
52953ff33114SBram Moolenaar  * Find the first entry in the quickfix list 'qfl' from buffer 'bnr'.
52963ff33114SBram Moolenaar  * The index of the entry is stored in 'errornr'.
52973ff33114SBram Moolenaar  * Returns NULL if an entry is not found.
52983ff33114SBram Moolenaar  */
52993ff33114SBram Moolenaar     static qfline_T *
qf_find_first_entry_in_buf(qf_list_T * qfl,int bnr,int * errornr)53003ff33114SBram Moolenaar qf_find_first_entry_in_buf(qf_list_T *qfl, int bnr, int *errornr)
53013ff33114SBram Moolenaar {
53023ff33114SBram Moolenaar     qfline_T	*qfp = NULL;
53033ff33114SBram Moolenaar     int		idx = 0;
53043ff33114SBram Moolenaar 
53053ff33114SBram Moolenaar     // Find the first entry in this file
53063ff33114SBram Moolenaar     FOR_ALL_QFL_ITEMS(qfl, qfp, idx)
53073ff33114SBram Moolenaar 	if (qfp->qf_fnum == bnr)
53083ff33114SBram Moolenaar 	    break;
53093ff33114SBram Moolenaar 
53103ff33114SBram Moolenaar     *errornr = idx;
53113ff33114SBram Moolenaar     return qfp;
53123ff33114SBram Moolenaar }
53133ff33114SBram Moolenaar 
53143ff33114SBram Moolenaar /*
53153ff33114SBram Moolenaar  * Find the first quickfix entry on the same line as 'entry'. Updates 'errornr'
53163ff33114SBram Moolenaar  * with the error number for the first entry. Assumes the entries are sorted in
53173ff33114SBram Moolenaar  * the quickfix list by line number.
53183ff33114SBram Moolenaar  */
53193ff33114SBram Moolenaar     static qfline_T *
qf_find_first_entry_on_line(qfline_T * entry,int * errornr)53203ff33114SBram Moolenaar qf_find_first_entry_on_line(qfline_T *entry, int *errornr)
53213ff33114SBram Moolenaar {
53223ff33114SBram Moolenaar     while (!got_int
53233ff33114SBram Moolenaar 	    && entry->qf_prev != NULL
53243ff33114SBram Moolenaar 	    && entry->qf_fnum == entry->qf_prev->qf_fnum
53253ff33114SBram Moolenaar 	    && entry->qf_lnum == entry->qf_prev->qf_lnum)
53263ff33114SBram Moolenaar     {
53273ff33114SBram Moolenaar 	entry = entry->qf_prev;
53283ff33114SBram Moolenaar 	--*errornr;
53293ff33114SBram Moolenaar     }
53303ff33114SBram Moolenaar 
53313ff33114SBram Moolenaar     return entry;
53323ff33114SBram Moolenaar }
53333ff33114SBram Moolenaar 
53343ff33114SBram Moolenaar /*
53353ff33114SBram Moolenaar  * Find the last quickfix entry on the same line as 'entry'. Updates 'errornr'
53363ff33114SBram Moolenaar  * with the error number for the last entry. Assumes the entries are sorted in
53373ff33114SBram Moolenaar  * the quickfix list by line number.
53383ff33114SBram Moolenaar  */
53393ff33114SBram Moolenaar     static qfline_T *
qf_find_last_entry_on_line(qfline_T * entry,int * errornr)53403ff33114SBram Moolenaar qf_find_last_entry_on_line(qfline_T *entry, int *errornr)
53413ff33114SBram Moolenaar {
53423ff33114SBram Moolenaar     while (!got_int &&
53433ff33114SBram Moolenaar 	    entry->qf_next != NULL
53443ff33114SBram Moolenaar 	    && entry->qf_fnum == entry->qf_next->qf_fnum
53453ff33114SBram Moolenaar 	    && entry->qf_lnum == entry->qf_next->qf_lnum)
53463ff33114SBram Moolenaar     {
53473ff33114SBram Moolenaar 	entry = entry->qf_next;
53483ff33114SBram Moolenaar 	++*errornr;
53493ff33114SBram Moolenaar     }
53503ff33114SBram Moolenaar 
53513ff33114SBram Moolenaar     return entry;
53523ff33114SBram Moolenaar }
53533ff33114SBram Moolenaar 
53543ff33114SBram Moolenaar /*
5355cf6a55c4SBram Moolenaar  * Returns TRUE if the specified quickfix entry is
5356cf6a55c4SBram Moolenaar  *   after the given line (linewise is TRUE)
5357cf6a55c4SBram Moolenaar  *   or after the line and column.
5358cf6a55c4SBram Moolenaar  */
5359cf6a55c4SBram Moolenaar     static int
qf_entry_after_pos(qfline_T * qfp,pos_T * pos,int linewise)5360cf6a55c4SBram Moolenaar qf_entry_after_pos(qfline_T *qfp, pos_T *pos, int linewise)
5361cf6a55c4SBram Moolenaar {
5362cf6a55c4SBram Moolenaar     if (linewise)
5363cf6a55c4SBram Moolenaar 	return qfp->qf_lnum > pos->lnum;
5364cf6a55c4SBram Moolenaar     else
5365cf6a55c4SBram Moolenaar 	return (qfp->qf_lnum > pos->lnum ||
5366cf6a55c4SBram Moolenaar 		(qfp->qf_lnum == pos->lnum && qfp->qf_col > pos->col));
5367cf6a55c4SBram Moolenaar }
5368cf6a55c4SBram Moolenaar 
5369cf6a55c4SBram Moolenaar /*
5370cf6a55c4SBram Moolenaar  * Returns TRUE if the specified quickfix entry is
5371cf6a55c4SBram Moolenaar  *   before the given line (linewise is TRUE)
5372cf6a55c4SBram Moolenaar  *   or before the line and column.
5373cf6a55c4SBram Moolenaar  */
5374cf6a55c4SBram Moolenaar     static int
qf_entry_before_pos(qfline_T * qfp,pos_T * pos,int linewise)5375cf6a55c4SBram Moolenaar qf_entry_before_pos(qfline_T *qfp, pos_T *pos, int linewise)
5376cf6a55c4SBram Moolenaar {
5377cf6a55c4SBram Moolenaar     if (linewise)
5378cf6a55c4SBram Moolenaar 	return qfp->qf_lnum < pos->lnum;
5379cf6a55c4SBram Moolenaar     else
5380cf6a55c4SBram Moolenaar 	return (qfp->qf_lnum < pos->lnum ||
5381cf6a55c4SBram Moolenaar 		(qfp->qf_lnum == pos->lnum && qfp->qf_col < pos->col));
5382cf6a55c4SBram Moolenaar }
5383cf6a55c4SBram Moolenaar 
5384cf6a55c4SBram Moolenaar /*
5385cf6a55c4SBram Moolenaar  * Returns TRUE if the specified quickfix entry is
5386cf6a55c4SBram Moolenaar  *   on or after the given line (linewise is TRUE)
5387cf6a55c4SBram Moolenaar  *   or on or after the line and column.
5388cf6a55c4SBram Moolenaar  */
5389cf6a55c4SBram Moolenaar     static int
qf_entry_on_or_after_pos(qfline_T * qfp,pos_T * pos,int linewise)5390cf6a55c4SBram Moolenaar qf_entry_on_or_after_pos(qfline_T *qfp, pos_T *pos, int linewise)
5391cf6a55c4SBram Moolenaar {
5392cf6a55c4SBram Moolenaar     if (linewise)
5393cf6a55c4SBram Moolenaar 	return qfp->qf_lnum >= pos->lnum;
5394cf6a55c4SBram Moolenaar     else
5395cf6a55c4SBram Moolenaar 	return (qfp->qf_lnum > pos->lnum ||
5396cf6a55c4SBram Moolenaar 		(qfp->qf_lnum == pos->lnum && qfp->qf_col >= pos->col));
5397cf6a55c4SBram Moolenaar }
5398cf6a55c4SBram Moolenaar 
5399cf6a55c4SBram Moolenaar /*
5400cf6a55c4SBram Moolenaar  * Returns TRUE if the specified quickfix entry is
5401cf6a55c4SBram Moolenaar  *   on or before the given line (linewise is TRUE)
5402cf6a55c4SBram Moolenaar  *   or on or before the line and column.
5403cf6a55c4SBram Moolenaar  */
5404cf6a55c4SBram Moolenaar     static int
qf_entry_on_or_before_pos(qfline_T * qfp,pos_T * pos,int linewise)5405cf6a55c4SBram Moolenaar qf_entry_on_or_before_pos(qfline_T *qfp, pos_T *pos, int linewise)
5406cf6a55c4SBram Moolenaar {
5407cf6a55c4SBram Moolenaar     if (linewise)
5408cf6a55c4SBram Moolenaar 	return qfp->qf_lnum <= pos->lnum;
5409cf6a55c4SBram Moolenaar     else
5410cf6a55c4SBram Moolenaar 	return (qfp->qf_lnum < pos->lnum ||
5411cf6a55c4SBram Moolenaar 		(qfp->qf_lnum == pos->lnum && qfp->qf_col <= pos->col));
5412cf6a55c4SBram Moolenaar }
5413cf6a55c4SBram Moolenaar 
5414cf6a55c4SBram Moolenaar /*
5415cf6a55c4SBram Moolenaar  * Find the first quickfix entry after position 'pos' in buffer 'bnr'.
5416cf6a55c4SBram Moolenaar  * If 'linewise' is TRUE, returns the entry after the specified line and treats
5417cf6a55c4SBram Moolenaar  * multiple entries on a single line as one. Otherwise returns the entry after
5418cf6a55c4SBram Moolenaar  * the specified line and column.
54193ff33114SBram Moolenaar  * 'qfp' points to the very first entry in the buffer and 'errornr' is the
54203ff33114SBram Moolenaar  * index of the very first entry in the quickfix list.
5421cf6a55c4SBram Moolenaar  * Returns NULL if an entry is not found after 'pos'.
54223ff33114SBram Moolenaar  */
54233ff33114SBram Moolenaar     static qfline_T *
qf_find_entry_after_pos(int bnr,pos_T * pos,int linewise,qfline_T * qfp,int * errornr)5424cf6a55c4SBram Moolenaar qf_find_entry_after_pos(
54253ff33114SBram Moolenaar 	int		bnr,
5426cf6a55c4SBram Moolenaar 	pos_T		*pos,
5427cf6a55c4SBram Moolenaar 	int		linewise,
54283ff33114SBram Moolenaar 	qfline_T	*qfp,
54293ff33114SBram Moolenaar 	int		*errornr)
54303ff33114SBram Moolenaar {
5431cf6a55c4SBram Moolenaar     if (qf_entry_after_pos(qfp, pos, linewise))
543232aa1020SBram Moolenaar 	// First entry is after position 'pos'
54333ff33114SBram Moolenaar 	return qfp;
54343ff33114SBram Moolenaar 
5435cf6a55c4SBram Moolenaar     // Find the entry just before or at the position 'pos'
54363ff33114SBram Moolenaar     while (qfp->qf_next != NULL
54373ff33114SBram Moolenaar 	    && qfp->qf_next->qf_fnum == bnr
5438cf6a55c4SBram Moolenaar 	    && qf_entry_on_or_before_pos(qfp->qf_next, pos, linewise))
54393ff33114SBram Moolenaar     {
54403ff33114SBram Moolenaar 	qfp = qfp->qf_next;
54413ff33114SBram Moolenaar 	++*errornr;
54423ff33114SBram Moolenaar     }
54433ff33114SBram Moolenaar 
54443ff33114SBram Moolenaar     if (qfp->qf_next == NULL || qfp->qf_next->qf_fnum != bnr)
5445cf6a55c4SBram Moolenaar 	// No entries found after position 'pos'
54463ff33114SBram Moolenaar 	return NULL;
54473ff33114SBram Moolenaar 
5448cf6a55c4SBram Moolenaar     // Use the entry just after position 'pos'
54493ff33114SBram Moolenaar     qfp = qfp->qf_next;
54503ff33114SBram Moolenaar     ++*errornr;
54513ff33114SBram Moolenaar 
54523ff33114SBram Moolenaar     return qfp;
54533ff33114SBram Moolenaar }
54543ff33114SBram Moolenaar 
54553ff33114SBram Moolenaar /*
5456cf6a55c4SBram Moolenaar  * Find the first quickfix entry before position 'pos' in buffer 'bnr'.
5457cf6a55c4SBram Moolenaar  * If 'linewise' is TRUE, returns the entry before the specified line and
5458cf6a55c4SBram Moolenaar  * treats multiple entries on a single line as one. Otherwise returns the entry
5459cf6a55c4SBram Moolenaar  * before the specified line and column.
54603ff33114SBram Moolenaar  * 'qfp' points to the very first entry in the buffer and 'errornr' is the
54613ff33114SBram Moolenaar  * index of the very first entry in the quickfix list.
5462cf6a55c4SBram Moolenaar  * Returns NULL if an entry is not found before 'pos'.
54633ff33114SBram Moolenaar  */
54643ff33114SBram Moolenaar     static qfline_T *
qf_find_entry_before_pos(int bnr,pos_T * pos,int linewise,qfline_T * qfp,int * errornr)5465cf6a55c4SBram Moolenaar qf_find_entry_before_pos(
54663ff33114SBram Moolenaar 	int		bnr,
5467cf6a55c4SBram Moolenaar 	pos_T		*pos,
5468cf6a55c4SBram Moolenaar 	int		linewise,
54693ff33114SBram Moolenaar 	qfline_T	*qfp,
54703ff33114SBram Moolenaar 	int		*errornr)
54713ff33114SBram Moolenaar {
5472cf6a55c4SBram Moolenaar     // Find the entry just before the position 'pos'
54733ff33114SBram Moolenaar     while (qfp->qf_next != NULL
54743ff33114SBram Moolenaar 	    && qfp->qf_next->qf_fnum == bnr
5475cf6a55c4SBram Moolenaar 	    && qf_entry_before_pos(qfp->qf_next, pos, linewise))
54763ff33114SBram Moolenaar     {
54773ff33114SBram Moolenaar 	qfp = qfp->qf_next;
54783ff33114SBram Moolenaar 	++*errornr;
54793ff33114SBram Moolenaar     }
54803ff33114SBram Moolenaar 
5481cf6a55c4SBram Moolenaar     if (qf_entry_on_or_after_pos(qfp, pos, linewise))
54823ff33114SBram Moolenaar 	return NULL;
54833ff33114SBram Moolenaar 
5484cf6a55c4SBram Moolenaar     if (linewise)
54853ff33114SBram Moolenaar 	// If multiple entries are on the same line, then use the first entry
54863ff33114SBram Moolenaar 	qfp = qf_find_first_entry_on_line(qfp, errornr);
54873ff33114SBram Moolenaar 
54883ff33114SBram Moolenaar     return qfp;
54893ff33114SBram Moolenaar }
54903ff33114SBram Moolenaar 
54913ff33114SBram Moolenaar /*
5492cf6a55c4SBram Moolenaar  * Find a quickfix entry in 'qfl' closest to position 'pos' in buffer 'bnr' in
54933ff33114SBram Moolenaar  * the direction 'dir'.
54943ff33114SBram Moolenaar  */
54953ff33114SBram Moolenaar     static qfline_T *
qf_find_closest_entry(qf_list_T * qfl,int bnr,pos_T * pos,int dir,int linewise,int * errornr)54963ff33114SBram Moolenaar qf_find_closest_entry(
54973ff33114SBram Moolenaar 	qf_list_T	*qfl,
54983ff33114SBram Moolenaar 	int		bnr,
5499cf6a55c4SBram Moolenaar 	pos_T		*pos,
55003ff33114SBram Moolenaar 	int		dir,
5501cf6a55c4SBram Moolenaar 	int		linewise,
55023ff33114SBram Moolenaar 	int		*errornr)
55033ff33114SBram Moolenaar {
55043ff33114SBram Moolenaar     qfline_T	*qfp;
55053ff33114SBram Moolenaar 
55063ff33114SBram Moolenaar     *errornr = 0;
55073ff33114SBram Moolenaar 
55083ff33114SBram Moolenaar     // Find the first entry in this file
55093ff33114SBram Moolenaar     qfp = qf_find_first_entry_in_buf(qfl, bnr, errornr);
55103ff33114SBram Moolenaar     if (qfp == NULL)
55113ff33114SBram Moolenaar 	return NULL;		// no entry in this file
55123ff33114SBram Moolenaar 
55133ff33114SBram Moolenaar     if (dir == FORWARD)
5514cf6a55c4SBram Moolenaar 	qfp = qf_find_entry_after_pos(bnr, pos, linewise, qfp, errornr);
55153ff33114SBram Moolenaar     else
5516cf6a55c4SBram Moolenaar 	qfp = qf_find_entry_before_pos(bnr, pos, linewise, qfp, errornr);
55173ff33114SBram Moolenaar 
55183ff33114SBram Moolenaar     return qfp;
55193ff33114SBram Moolenaar }
55203ff33114SBram Moolenaar 
55213ff33114SBram Moolenaar /*
5522cf6a55c4SBram Moolenaar  * Get the nth quickfix entry below the specified entry.  Searches forward in
5523cf6a55c4SBram Moolenaar  * the list. If linewise is TRUE, then treat multiple entries on a single line
5524cf6a55c4SBram Moolenaar  * as one.
55253ff33114SBram Moolenaar  */
552664416127SBram Moolenaar     static void
qf_get_nth_below_entry(qfline_T * entry_arg,int n,int linewise,int * errornr)5527d6a98a3aSBram Moolenaar qf_get_nth_below_entry(qfline_T *entry_arg, int n, int linewise, int *errornr)
55283ff33114SBram Moolenaar {
5529d6a98a3aSBram Moolenaar     qfline_T *entry = entry_arg;
5530d6a98a3aSBram Moolenaar 
55313ff33114SBram Moolenaar     while (n-- > 0 && !got_int)
55323ff33114SBram Moolenaar     {
55333ff33114SBram Moolenaar 	int		first_errornr = *errornr;
55343ff33114SBram Moolenaar 
5535cf6a55c4SBram Moolenaar 	if (linewise)
55363ff33114SBram Moolenaar 	    // Treat all the entries on the same line in this file as one
55373ff33114SBram Moolenaar 	    entry = qf_find_last_entry_on_line(entry, errornr);
55383ff33114SBram Moolenaar 
55393ff33114SBram Moolenaar 	if (entry->qf_next == NULL
55403ff33114SBram Moolenaar 		|| entry->qf_next->qf_fnum != entry->qf_fnum)
55413ff33114SBram Moolenaar 	{
5542cf6a55c4SBram Moolenaar 	    if (linewise)
55433ff33114SBram Moolenaar 		*errornr = first_errornr;
55443ff33114SBram Moolenaar 	    break;
55453ff33114SBram Moolenaar 	}
55463ff33114SBram Moolenaar 
55473ff33114SBram Moolenaar 	entry = entry->qf_next;
55483ff33114SBram Moolenaar 	++*errornr;
55493ff33114SBram Moolenaar     }
55503ff33114SBram Moolenaar }
55513ff33114SBram Moolenaar 
55523ff33114SBram Moolenaar /*
5553cf6a55c4SBram Moolenaar  * Get the nth quickfix entry above the specified entry.  Searches backwards in
5554cf6a55c4SBram Moolenaar  * the list. If linewise is TRUE, then treat multiple entries on a single line
5555cf6a55c4SBram Moolenaar  * as one.
55563ff33114SBram Moolenaar  */
555764416127SBram Moolenaar     static void
qf_get_nth_above_entry(qfline_T * entry,int n,int linewise,int * errornr)5558cf6a55c4SBram Moolenaar qf_get_nth_above_entry(qfline_T *entry, int n, int linewise, int *errornr)
55593ff33114SBram Moolenaar {
55603ff33114SBram Moolenaar     while (n-- > 0 && !got_int)
55613ff33114SBram Moolenaar     {
55623ff33114SBram Moolenaar 	if (entry->qf_prev == NULL
55633ff33114SBram Moolenaar 		|| entry->qf_prev->qf_fnum != entry->qf_fnum)
55643ff33114SBram Moolenaar 	    break;
55653ff33114SBram Moolenaar 
55663ff33114SBram Moolenaar 	entry = entry->qf_prev;
55673ff33114SBram Moolenaar 	--*errornr;
55683ff33114SBram Moolenaar 
55693ff33114SBram Moolenaar 	// If multiple entries are on the same line, then use the first entry
5570cf6a55c4SBram Moolenaar 	if (linewise)
55713ff33114SBram Moolenaar 	    entry = qf_find_first_entry_on_line(entry, errornr);
55723ff33114SBram Moolenaar     }
55733ff33114SBram Moolenaar }
55743ff33114SBram Moolenaar 
55753ff33114SBram Moolenaar /*
5576cf6a55c4SBram Moolenaar  * Find the n'th quickfix entry adjacent to position 'pos' in buffer 'bnr' in
5577cf6a55c4SBram Moolenaar  * the specified direction.  Returns the error number in the quickfix list or 0
5578cf6a55c4SBram Moolenaar  * if an entry is not found.
55793ff33114SBram Moolenaar  */
55803ff33114SBram Moolenaar     static int
qf_find_nth_adj_entry(qf_list_T * qfl,int bnr,pos_T * pos,int n,int dir,int linewise)5581cf6a55c4SBram Moolenaar qf_find_nth_adj_entry(
5582cf6a55c4SBram Moolenaar 	qf_list_T	*qfl,
5583cf6a55c4SBram Moolenaar 	int		bnr,
5584cf6a55c4SBram Moolenaar 	pos_T		*pos,
5585cf6a55c4SBram Moolenaar 	int		n,
5586cf6a55c4SBram Moolenaar 	int		dir,
5587cf6a55c4SBram Moolenaar 	int		linewise)
55883ff33114SBram Moolenaar {
55893ff33114SBram Moolenaar     qfline_T	*adj_entry;
55903ff33114SBram Moolenaar     int		errornr;
55913ff33114SBram Moolenaar 
5592cf6a55c4SBram Moolenaar     // Find an entry closest to the specified position
5593cf6a55c4SBram Moolenaar     adj_entry = qf_find_closest_entry(qfl, bnr, pos, dir, linewise, &errornr);
55943ff33114SBram Moolenaar     if (adj_entry == NULL)
55953ff33114SBram Moolenaar 	return 0;
55963ff33114SBram Moolenaar 
55973ff33114SBram Moolenaar     if (--n > 0)
55983ff33114SBram Moolenaar     {
55993ff33114SBram Moolenaar 	// Go to the n'th entry in the current buffer
56003ff33114SBram Moolenaar 	if (dir == FORWARD)
560164416127SBram Moolenaar 	    qf_get_nth_below_entry(adj_entry, n, linewise, &errornr);
56023ff33114SBram Moolenaar 	else
560364416127SBram Moolenaar 	    qf_get_nth_above_entry(adj_entry, n, linewise, &errornr);
56043ff33114SBram Moolenaar     }
56053ff33114SBram Moolenaar 
56063ff33114SBram Moolenaar     return errornr;
56073ff33114SBram Moolenaar }
56083ff33114SBram Moolenaar 
56093ff33114SBram Moolenaar /*
5610cf6a55c4SBram Moolenaar  * Jump to a quickfix entry in the current file nearest to the current line or
5611cf6a55c4SBram Moolenaar  * current line/col.
5612cf6a55c4SBram Moolenaar  * ":cabove", ":cbelow", ":labove", ":lbelow", ":cafter", ":cbefore",
5613cf6a55c4SBram Moolenaar  * ":lafter" and ":lbefore" commands
56143ff33114SBram Moolenaar  */
56153ff33114SBram Moolenaar     void
ex_cbelow(exarg_T * eap)56163ff33114SBram Moolenaar ex_cbelow(exarg_T *eap)
56173ff33114SBram Moolenaar {
56183ff33114SBram Moolenaar     qf_info_T	*qi;
56193ff33114SBram Moolenaar     qf_list_T	*qfl;
56203ff33114SBram Moolenaar     int		dir;
56213ff33114SBram Moolenaar     int		buf_has_flag;
56223ff33114SBram Moolenaar     int		errornr = 0;
5623cf6a55c4SBram Moolenaar     pos_T	pos;
56243ff33114SBram Moolenaar 
56253ff33114SBram Moolenaar     if (eap->addr_count > 0 && eap->line2 <= 0)
56263ff33114SBram Moolenaar     {
5627108010aaSBram Moolenaar 	emsg(_(e_invalid_range));
56283ff33114SBram Moolenaar 	return;
56293ff33114SBram Moolenaar     }
56303ff33114SBram Moolenaar 
56313ff33114SBram Moolenaar     // Check whether the current buffer has any quickfix entries
5632cf6a55c4SBram Moolenaar     if (eap->cmdidx == CMD_cabove || eap->cmdidx == CMD_cbelow
5633cf6a55c4SBram Moolenaar 	    || eap->cmdidx == CMD_cbefore || eap->cmdidx == CMD_cafter)
56343ff33114SBram Moolenaar 	buf_has_flag = BUF_HAS_QF_ENTRY;
56353ff33114SBram Moolenaar     else
56363ff33114SBram Moolenaar 	buf_has_flag = BUF_HAS_LL_ENTRY;
56373ff33114SBram Moolenaar     if (!(curbuf->b_has_qf_entry & buf_has_flag))
56383ff33114SBram Moolenaar     {
5639e29a27f6SBram Moolenaar 	emsg(_(e_no_errors));
56403ff33114SBram Moolenaar 	return;
56413ff33114SBram Moolenaar     }
56423ff33114SBram Moolenaar 
56433ff33114SBram Moolenaar     if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
56443ff33114SBram Moolenaar 	return;
56453ff33114SBram Moolenaar 
56463ff33114SBram Moolenaar     qfl = qf_get_curlist(qi);
56473ff33114SBram Moolenaar     // check if the list has valid errors
56483ff33114SBram Moolenaar     if (!qf_list_has_valid_entries(qfl))
56493ff33114SBram Moolenaar     {
5650e29a27f6SBram Moolenaar 	emsg(_(e_no_errors));
56513ff33114SBram Moolenaar 	return;
56523ff33114SBram Moolenaar     }
56533ff33114SBram Moolenaar 
5654cf6a55c4SBram Moolenaar     if (eap->cmdidx == CMD_cbelow
5655cf6a55c4SBram Moolenaar 	    || eap->cmdidx == CMD_lbelow
5656cf6a55c4SBram Moolenaar 	    || eap->cmdidx == CMD_cafter
5657cf6a55c4SBram Moolenaar 	    || eap->cmdidx == CMD_lafter)
5658cf6a55c4SBram Moolenaar 	// Forward motion commands
56593ff33114SBram Moolenaar 	dir = FORWARD;
56603ff33114SBram Moolenaar     else
56613ff33114SBram Moolenaar 	dir = BACKWARD;
56623ff33114SBram Moolenaar 
5663cf6a55c4SBram Moolenaar     pos = curwin->w_cursor;
5664cf6a55c4SBram Moolenaar     // A quickfix entry column number is 1 based whereas cursor column
5665cf6a55c4SBram Moolenaar     // number is 0 based. Adjust the column number.
5666cf6a55c4SBram Moolenaar     pos.col++;
5667cf6a55c4SBram Moolenaar     errornr = qf_find_nth_adj_entry(qfl, curbuf->b_fnum, &pos,
5668cf6a55c4SBram Moolenaar 				eap->addr_count > 0 ? eap->line2 : 0, dir,
5669cf6a55c4SBram Moolenaar 				eap->cmdidx == CMD_cbelow
5670cf6a55c4SBram Moolenaar 					|| eap->cmdidx == CMD_lbelow
5671cf6a55c4SBram Moolenaar 					|| eap->cmdidx == CMD_cabove
5672cf6a55c4SBram Moolenaar 					|| eap->cmdidx == CMD_labove);
56733ff33114SBram Moolenaar 
56743ff33114SBram Moolenaar     if (errornr > 0)
56753ff33114SBram Moolenaar 	qf_jump(qi, 0, errornr, FALSE);
56763ff33114SBram Moolenaar     else
56773ff33114SBram Moolenaar 	emsg(_(e_no_more_items));
56783ff33114SBram Moolenaar }
56793ff33114SBram Moolenaar 
56803ff33114SBram Moolenaar /*
5681a16123a6SBram Moolenaar  * Return the autocmd name for the :cfile Ex commands
5682a16123a6SBram Moolenaar  */
5683a16123a6SBram Moolenaar     static char_u *
cfile_get_auname(cmdidx_T cmdidx)5684a16123a6SBram Moolenaar cfile_get_auname(cmdidx_T cmdidx)
5685a16123a6SBram Moolenaar {
5686a16123a6SBram Moolenaar     switch (cmdidx)
5687a16123a6SBram Moolenaar     {
5688a16123a6SBram Moolenaar 	case CMD_cfile:	    return (char_u *)"cfile";
5689a16123a6SBram Moolenaar 	case CMD_cgetfile:  return (char_u *)"cgetfile";
5690a16123a6SBram Moolenaar 	case CMD_caddfile:  return (char_u *)"caddfile";
5691a16123a6SBram Moolenaar 	case CMD_lfile:	    return (char_u *)"lfile";
5692a16123a6SBram Moolenaar 	case CMD_lgetfile:  return (char_u *)"lgetfile";
5693a16123a6SBram Moolenaar 	case CMD_laddfile:  return (char_u *)"laddfile";
5694a16123a6SBram Moolenaar 	default:	    return NULL;
5695a16123a6SBram Moolenaar     }
5696a16123a6SBram Moolenaar }
5697a16123a6SBram Moolenaar 
5698a16123a6SBram Moolenaar /*
569987e25fdfSBram Moolenaar  * ":cfile"/":cgetfile"/":caddfile" commands.
5700d12f5c17SBram Moolenaar  * ":lfile"/":lgetfile"/":laddfile" commands.
5701071d4279SBram Moolenaar  */
5702071d4279SBram Moolenaar     void
ex_cfile(exarg_T * eap)570305540976SBram Moolenaar ex_cfile(exarg_T *eap)
5704071d4279SBram Moolenaar {
57052c7292dcSBram Moolenaar     char_u	*enc = NULL;
5706d12f5c17SBram Moolenaar     win_T	*wp = NULL;
57078b6144bdSBram Moolenaar     qf_info_T	*qi = &ql_info;
57088ec1f852SBram Moolenaar     char_u	*au_name = NULL;
570900bf8cd2SBram Moolenaar     int_u	save_qfid = 0;		// init for gcc
57101ed2276fSBram Moolenaar     int		res;
5711d12f5c17SBram Moolenaar 
5712a16123a6SBram Moolenaar     au_name = cfile_get_auname(eap->cmdidx);
57136a0cc916SBram Moolenaar     if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
57146a0cc916SBram Moolenaar 							NULL, FALSE, curbuf))
57156a0cc916SBram Moolenaar     {
57166a0cc916SBram Moolenaar #ifdef FEAT_EVAL
57176a0cc916SBram Moolenaar 	if (aborting())
57186a0cc916SBram Moolenaar 	    return;
57196a0cc916SBram Moolenaar #endif
57206a0cc916SBram Moolenaar     }
5721a16123a6SBram Moolenaar 
57222c7292dcSBram Moolenaar     enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc;
57239028b10dSBram Moolenaar #ifdef FEAT_BROWSE
5724e1004401SBram Moolenaar     if (cmdmod.cmod_flags & CMOD_BROWSE)
57259028b10dSBram Moolenaar     {
57269028b10dSBram Moolenaar 	char_u *browse_file = do_browse(0, (char_u *)_("Error file"), eap->arg,
5727c36651b4SBram Moolenaar 				   NULL, NULL,
5728c36651b4SBram Moolenaar 				   (char_u *)_(BROWSE_FILTER_ALL_FILES), NULL);
57299028b10dSBram Moolenaar 	if (browse_file == NULL)
57309028b10dSBram Moolenaar 	    return;
57319028b10dSBram Moolenaar 	set_string_option_direct((char_u *)"ef", -1, browse_file, OPT_FREE, 0);
57329028b10dSBram Moolenaar 	vim_free(browse_file);
57339028b10dSBram Moolenaar     }
57349028b10dSBram Moolenaar     else
57359028b10dSBram Moolenaar #endif
5736071d4279SBram Moolenaar     if (*eap->arg != NUL)
57375e3cb7e8SBram Moolenaar 	set_string_option_direct((char_u *)"ef", -1, eap->arg, OPT_FREE, 0);
573887e25fdfSBram Moolenaar 
573939665959SBram Moolenaar     if (is_loclist_cmd(eap->cmdidx))
574014a4deb0SBram Moolenaar 	wp = curwin;
574114a4deb0SBram Moolenaar 
57429f84ded3SBram Moolenaar     incr_quickfix_busy();
57439f84ded3SBram Moolenaar 
574400bf8cd2SBram Moolenaar     // This function is used by the :cfile, :cgetfile and :caddfile
574500bf8cd2SBram Moolenaar     // commands.
574600bf8cd2SBram Moolenaar     // :cfile always creates a new quickfix list and jumps to the
574700bf8cd2SBram Moolenaar     // first error.
574800bf8cd2SBram Moolenaar     // :cgetfile creates a new quickfix list but doesn't jump to the
574900bf8cd2SBram Moolenaar     // first error.
575000bf8cd2SBram Moolenaar     // :caddfile adds to an existing quickfix list. If there is no
575100bf8cd2SBram Moolenaar     // quickfix list then a new list is created.
57521ed2276fSBram Moolenaar     res = qf_init(wp, p_ef, p_efm, (eap->cmdidx != CMD_caddfile
57538b62e310SBram Moolenaar 			&& eap->cmdidx != CMD_laddfile),
57548b62e310SBram Moolenaar 			qf_cmdtitle(*eap->cmdlinep), enc);
5755b254af31SBram Moolenaar     if (wp != NULL)
5756531b9a3aSBram Moolenaar     {
5757b254af31SBram Moolenaar 	qi = GET_LOC_LIST(wp);
5758531b9a3aSBram Moolenaar 	if (qi == NULL)
57599f84ded3SBram Moolenaar 	{
57609f84ded3SBram Moolenaar 	    decr_quickfix_busy();
5761531b9a3aSBram Moolenaar 	    return;
5762531b9a3aSBram Moolenaar 	}
57639f84ded3SBram Moolenaar     }
5764531b9a3aSBram Moolenaar     if (res >= 0)
57654aa47b28SBram Moolenaar 	qf_list_changed(qf_get_curlist(qi));
57664aa47b28SBram Moolenaar     save_qfid = qf_get_curlist(qi)->qf_id;
57678ec1f852SBram Moolenaar     if (au_name != NULL)
57688ec1f852SBram Moolenaar 	apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, NULL, FALSE, curbuf);
57690549a1e1SBram Moolenaar 
5770531b9a3aSBram Moolenaar     // Jump to the first error for a new list and if autocmds didn't
5771531b9a3aSBram Moolenaar     // free the list.
5772531b9a3aSBram Moolenaar     if (res > 0 && (eap->cmdidx == CMD_cfile || eap->cmdidx == CMD_lfile)
5773531b9a3aSBram Moolenaar 	    && qflist_valid(wp, save_qfid))
57748d8a65e3SBram Moolenaar 	// display the first error
57758d8a65e3SBram Moolenaar 	qf_jump_first(qi, save_qfid, eap->forceit);
57769f84ded3SBram Moolenaar 
57779f84ded3SBram Moolenaar     decr_quickfix_busy();
5778071d4279SBram Moolenaar }
5779e1bb879fSBram Moolenaar 
5780e1bb879fSBram Moolenaar /*
578175b0a888SBram Moolenaar  * Return the vimgrep autocmd name.
578275b0a888SBram Moolenaar  */
578375b0a888SBram Moolenaar     static char_u *
vgr_get_auname(cmdidx_T cmdidx)578475b0a888SBram Moolenaar vgr_get_auname(cmdidx_T cmdidx)
578575b0a888SBram Moolenaar {
578675b0a888SBram Moolenaar     switch (cmdidx)
578775b0a888SBram Moolenaar     {
578875b0a888SBram Moolenaar 	case CMD_vimgrep:     return (char_u *)"vimgrep";
578975b0a888SBram Moolenaar 	case CMD_lvimgrep:    return (char_u *)"lvimgrep";
579075b0a888SBram Moolenaar 	case CMD_vimgrepadd:  return (char_u *)"vimgrepadd";
579175b0a888SBram Moolenaar 	case CMD_lvimgrepadd: return (char_u *)"lvimgrepadd";
579275b0a888SBram Moolenaar 	case CMD_grep:	      return (char_u *)"grep";
579375b0a888SBram Moolenaar 	case CMD_lgrep:	      return (char_u *)"lgrep";
579475b0a888SBram Moolenaar 	case CMD_grepadd:     return (char_u *)"grepadd";
579575b0a888SBram Moolenaar 	case CMD_lgrepadd:    return (char_u *)"lgrepadd";
579675b0a888SBram Moolenaar 	default: return NULL;
579775b0a888SBram Moolenaar     }
579875b0a888SBram Moolenaar }
579975b0a888SBram Moolenaar 
580075b0a888SBram Moolenaar /*
580175b0a888SBram Moolenaar  * Initialize the regmatch used by vimgrep for pattern "s".
580275b0a888SBram Moolenaar  */
580375b0a888SBram Moolenaar     static void
vgr_init_regmatch(regmmatch_T * regmatch,char_u * s)580475b0a888SBram Moolenaar vgr_init_regmatch(regmmatch_T *regmatch, char_u *s)
580575b0a888SBram Moolenaar {
580600bf8cd2SBram Moolenaar     // Get the search pattern: either white-separated or enclosed in //
580775b0a888SBram Moolenaar     regmatch->regprog = NULL;
580875b0a888SBram Moolenaar 
580975b0a888SBram Moolenaar     if (s == NULL || *s == NUL)
581075b0a888SBram Moolenaar     {
581100bf8cd2SBram Moolenaar 	// Pattern is empty, use last search pattern.
581275b0a888SBram Moolenaar 	if (last_search_pat() == NULL)
581375b0a888SBram Moolenaar 	{
5814e29a27f6SBram Moolenaar 	    emsg(_(e_no_previous_regular_expression));
581575b0a888SBram Moolenaar 	    return;
581675b0a888SBram Moolenaar 	}
581775b0a888SBram Moolenaar 	regmatch->regprog = vim_regcomp(last_search_pat(), RE_MAGIC);
581875b0a888SBram Moolenaar     }
581975b0a888SBram Moolenaar     else
582075b0a888SBram Moolenaar 	regmatch->regprog = vim_regcomp(s, RE_MAGIC);
582175b0a888SBram Moolenaar 
582275b0a888SBram Moolenaar     regmatch->rmm_ic = p_ic;
582375b0a888SBram Moolenaar     regmatch->rmm_maxcol = 0;
582475b0a888SBram Moolenaar }
582575b0a888SBram Moolenaar 
582675b0a888SBram Moolenaar /*
582775b0a888SBram Moolenaar  * Display a file name when vimgrep is running.
582875b0a888SBram Moolenaar  */
582975b0a888SBram Moolenaar     static void
vgr_display_fname(char_u * fname)583075b0a888SBram Moolenaar vgr_display_fname(char_u *fname)
583175b0a888SBram Moolenaar {
583275b0a888SBram Moolenaar     char_u	*p;
583375b0a888SBram Moolenaar 
583475b0a888SBram Moolenaar     msg_start();
583575b0a888SBram Moolenaar     p = msg_strtrunc(fname, TRUE);
583675b0a888SBram Moolenaar     if (p == NULL)
583775b0a888SBram Moolenaar 	msg_outtrans(fname);
583875b0a888SBram Moolenaar     else
583975b0a888SBram Moolenaar     {
584075b0a888SBram Moolenaar 	msg_outtrans(p);
584175b0a888SBram Moolenaar 	vim_free(p);
584275b0a888SBram Moolenaar     }
584375b0a888SBram Moolenaar     msg_clr_eos();
584400bf8cd2SBram Moolenaar     msg_didout = FALSE;	    // overwrite this message
584500bf8cd2SBram Moolenaar     msg_nowait = TRUE;	    // don't wait for this message
584675b0a888SBram Moolenaar     msg_col = 0;
584775b0a888SBram Moolenaar     out_flush();
584875b0a888SBram Moolenaar }
584975b0a888SBram Moolenaar 
585075b0a888SBram Moolenaar /*
585175b0a888SBram Moolenaar  * Load a dummy buffer to search for a pattern using vimgrep.
585275b0a888SBram Moolenaar  */
585375b0a888SBram Moolenaar     static buf_T *
vgr_load_dummy_buf(char_u * fname,char_u * dirname_start,char_u * dirname_now)585475b0a888SBram Moolenaar vgr_load_dummy_buf(
585575b0a888SBram Moolenaar 	char_u *fname,
585675b0a888SBram Moolenaar 	char_u *dirname_start,
585775b0a888SBram Moolenaar 	char_u *dirname_now)
585875b0a888SBram Moolenaar {
585975b0a888SBram Moolenaar     int		save_mls;
586075b0a888SBram Moolenaar #if defined(FEAT_SYN_HL)
586175b0a888SBram Moolenaar     char_u	*save_ei = NULL;
586275b0a888SBram Moolenaar #endif
586375b0a888SBram Moolenaar     buf_T	*buf;
586475b0a888SBram Moolenaar 
586575b0a888SBram Moolenaar #if defined(FEAT_SYN_HL)
586600bf8cd2SBram Moolenaar     // Don't do Filetype autocommands to avoid loading syntax and
586700bf8cd2SBram Moolenaar     // indent scripts, a great speed improvement.
586875b0a888SBram Moolenaar     save_ei = au_event_disable(",Filetype");
586975b0a888SBram Moolenaar #endif
587000bf8cd2SBram Moolenaar     // Don't use modelines here, it's useless.
587175b0a888SBram Moolenaar     save_mls = p_mls;
587275b0a888SBram Moolenaar     p_mls = 0;
587375b0a888SBram Moolenaar 
587400bf8cd2SBram Moolenaar     // Load file into a buffer, so that 'fileencoding' is detected,
587500bf8cd2SBram Moolenaar     // autocommands applied, etc.
587675b0a888SBram Moolenaar     buf = load_dummy_buffer(fname, dirname_start, dirname_now);
587775b0a888SBram Moolenaar 
587875b0a888SBram Moolenaar     p_mls = save_mls;
587975b0a888SBram Moolenaar #if defined(FEAT_SYN_HL)
588075b0a888SBram Moolenaar     au_event_restore(save_ei);
588175b0a888SBram Moolenaar #endif
588275b0a888SBram Moolenaar 
588375b0a888SBram Moolenaar     return buf;
588475b0a888SBram Moolenaar }
588575b0a888SBram Moolenaar 
588675b0a888SBram Moolenaar /*
58874aa47b28SBram Moolenaar  * Check whether a quickfix/location list is valid. Autocmds may remove or
58884aa47b28SBram Moolenaar  * change a quickfix list when vimgrep is running. If the list is not found,
58894aa47b28SBram Moolenaar  * create a new list.
589075b0a888SBram Moolenaar  */
589175b0a888SBram Moolenaar     static int
vgr_qflist_valid(win_T * wp,qf_info_T * qi,int_u qfid,char_u * title)589275b0a888SBram Moolenaar vgr_qflist_valid(
5893e1bb879fSBram Moolenaar 	win_T	    *wp,
589475b0a888SBram Moolenaar 	qf_info_T   *qi,
5895e1bb879fSBram Moolenaar 	int_u	    qfid,
589675b0a888SBram Moolenaar 	char_u	    *title)
589775b0a888SBram Moolenaar {
589800bf8cd2SBram Moolenaar     // Verify that the quickfix/location list was not freed by an autocmd
5899e1bb879fSBram Moolenaar     if (!qflist_valid(wp, qfid))
590075b0a888SBram Moolenaar     {
5901e1bb879fSBram Moolenaar 	if (wp != NULL)
590275b0a888SBram Moolenaar 	{
590300bf8cd2SBram Moolenaar 	    // An autocmd has freed the location list.
59044d170af0SBram Moolenaar 	    emsg(_(e_current_location_list_was_changed));
590575b0a888SBram Moolenaar 	    return FALSE;
590675b0a888SBram Moolenaar 	}
5907e1bb879fSBram Moolenaar 	else
590875b0a888SBram Moolenaar 	{
590900bf8cd2SBram Moolenaar 	    // Quickfix list is not found, create a new one.
5910e1bb879fSBram Moolenaar 	    qf_new_list(qi, title);
5911e1bb879fSBram Moolenaar 	    return TRUE;
5912e1bb879fSBram Moolenaar 	}
5913e1bb879fSBram Moolenaar     }
591475b0a888SBram Moolenaar 
591590f1e2b7SBram Moolenaar     if (qf_restore_list(qi, qfid) == FAIL)
591690f1e2b7SBram Moolenaar 	return FALSE;
591775b0a888SBram Moolenaar 
591875b0a888SBram Moolenaar     return TRUE;
591975b0a888SBram Moolenaar }
592075b0a888SBram Moolenaar 
592175b0a888SBram Moolenaar /*
592275b0a888SBram Moolenaar  * Search for a pattern in all the lines in a buffer and add the matching lines
592375b0a888SBram Moolenaar  * to a quickfix list.
592475b0a888SBram Moolenaar  */
592575b0a888SBram Moolenaar     static int
vgr_match_buflines(qf_list_T * qfl,char_u * fname,buf_T * buf,char_u * spat,regmmatch_T * regmatch,long * tomatch,int duplicate_name,int flags)592675b0a888SBram Moolenaar vgr_match_buflines(
59279afe5e9cSBram Moolenaar 	qf_list_T   *qfl,
592875b0a888SBram Moolenaar 	char_u	    *fname,
592975b0a888SBram Moolenaar 	buf_T	    *buf,
5930bb01a1efSYegappan Lakshmanan 	char_u	    *spat,
593175b0a888SBram Moolenaar 	regmmatch_T *regmatch,
59321c299434SBram Moolenaar 	long	    *tomatch,
593375b0a888SBram Moolenaar 	int	    duplicate_name,
593475b0a888SBram Moolenaar 	int	    flags)
593575b0a888SBram Moolenaar {
593675b0a888SBram Moolenaar     int		found_match = FALSE;
593775b0a888SBram Moolenaar     long	lnum;
593875b0a888SBram Moolenaar     colnr_T	col;
5939551c1aedSBram Moolenaar     int		pat_len = (int)STRLEN(spat);
594075b0a888SBram Moolenaar 
59411c299434SBram Moolenaar     for (lnum = 1; lnum <= buf->b_ml.ml_line_count && *tomatch > 0; ++lnum)
594275b0a888SBram Moolenaar     {
594375b0a888SBram Moolenaar 	col = 0;
5944bb01a1efSYegappan Lakshmanan 	if (!(flags & VGR_FUZZY))
5945bb01a1efSYegappan Lakshmanan 	{
5946bb01a1efSYegappan Lakshmanan 	    // Regular expression match
594775b0a888SBram Moolenaar 	    while (vim_regexec_multi(regmatch, curwin, buf, lnum,
594875b0a888SBram Moolenaar 			col, NULL, NULL) > 0)
594975b0a888SBram Moolenaar 	    {
595000bf8cd2SBram Moolenaar 		// Pass the buffer number so that it gets used even for a
595100bf8cd2SBram Moolenaar 		// dummy buffer, unless duplicate_name is set, then the
595200bf8cd2SBram Moolenaar 		// buffer will be wiped out below.
59539afe5e9cSBram Moolenaar 		if (qf_add_entry(qfl,
595400bf8cd2SBram Moolenaar 			    NULL,	// dir
595575b0a888SBram Moolenaar 			    fname,
5956d76ce852SBram Moolenaar 			    NULL,
595775b0a888SBram Moolenaar 			    duplicate_name ? 0 : buf->b_fnum,
595875b0a888SBram Moolenaar 			    ml_get_buf(buf,
595975b0a888SBram Moolenaar 				regmatch->startpos[0].lnum + lnum, FALSE),
596075b0a888SBram Moolenaar 			    regmatch->startpos[0].lnum + lnum,
59616864efa5Sthinca 			    regmatch->endpos[0].lnum + lnum,
596275b0a888SBram Moolenaar 			    regmatch->startpos[0].col + 1,
59636864efa5Sthinca 			    regmatch->endpos[0].col + 1,
596400bf8cd2SBram Moolenaar 			    FALSE,	// vis_col
596500bf8cd2SBram Moolenaar 			    NULL,	// search pattern
596600bf8cd2SBram Moolenaar 			    0,		// nr
596700bf8cd2SBram Moolenaar 			    0,		// type
596800bf8cd2SBram Moolenaar 			    TRUE	// valid
596995946f12SBram Moolenaar 			    ) == QF_FAIL)
597075b0a888SBram Moolenaar 		{
597175b0a888SBram Moolenaar 		    got_int = TRUE;
597275b0a888SBram Moolenaar 		    break;
597375b0a888SBram Moolenaar 		}
597475b0a888SBram Moolenaar 		found_match = TRUE;
59751c299434SBram Moolenaar 		if (--*tomatch == 0)
597675b0a888SBram Moolenaar 		    break;
597775b0a888SBram Moolenaar 		if ((flags & VGR_GLOBAL) == 0
597875b0a888SBram Moolenaar 			|| regmatch->endpos[0].lnum > 0)
597975b0a888SBram Moolenaar 		    break;
598075b0a888SBram Moolenaar 		col = regmatch->endpos[0].col
598175b0a888SBram Moolenaar 		    + (col == regmatch->endpos[0].col);
598275b0a888SBram Moolenaar 		if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, FALSE)))
598375b0a888SBram Moolenaar 		    break;
598475b0a888SBram Moolenaar 	    }
5985bb01a1efSYegappan Lakshmanan 	}
5986bb01a1efSYegappan Lakshmanan 	else
5987bb01a1efSYegappan Lakshmanan 	{
5988bb01a1efSYegappan Lakshmanan 	    char_u  *str = ml_get_buf(buf, lnum, FALSE);
5989bb01a1efSYegappan Lakshmanan 	    int	    score;
5990bb01a1efSYegappan Lakshmanan 	    int_u   matches[MAX_FUZZY_MATCHES];
5991eeec2548SK.Takata 	    int_u   sz = ARRAY_LENGTH(matches);
5992bb01a1efSYegappan Lakshmanan 
5993bb01a1efSYegappan Lakshmanan 	    // Fuzzy string match
5994bb01a1efSYegappan Lakshmanan 	    while (fuzzy_match(str + col, spat, FALSE, &score, matches, sz) > 0)
5995bb01a1efSYegappan Lakshmanan 	    {
5996bb01a1efSYegappan Lakshmanan 		// Pass the buffer number so that it gets used even for a
5997bb01a1efSYegappan Lakshmanan 		// dummy buffer, unless duplicate_name is set, then the
5998bb01a1efSYegappan Lakshmanan 		// buffer will be wiped out below.
5999bb01a1efSYegappan Lakshmanan 		if (qf_add_entry(qfl,
6000bb01a1efSYegappan Lakshmanan 			    NULL,	// dir
6001bb01a1efSYegappan Lakshmanan 			    fname,
6002bb01a1efSYegappan Lakshmanan 			    NULL,
6003bb01a1efSYegappan Lakshmanan 			    duplicate_name ? 0 : buf->b_fnum,
6004bb01a1efSYegappan Lakshmanan 			    str,
6005bb01a1efSYegappan Lakshmanan 			    lnum,
60066864efa5Sthinca 			    0,
6007bb01a1efSYegappan Lakshmanan 			    matches[0] + col + 1,
60086864efa5Sthinca 			    0,
6009bb01a1efSYegappan Lakshmanan 			    FALSE,	// vis_col
6010bb01a1efSYegappan Lakshmanan 			    NULL,	// search pattern
6011bb01a1efSYegappan Lakshmanan 			    0,		// nr
6012bb01a1efSYegappan Lakshmanan 			    0,		// type
6013bb01a1efSYegappan Lakshmanan 			    TRUE	// valid
6014bb01a1efSYegappan Lakshmanan 			    ) == QF_FAIL)
6015bb01a1efSYegappan Lakshmanan 		{
6016bb01a1efSYegappan Lakshmanan 		    got_int = TRUE;
6017bb01a1efSYegappan Lakshmanan 		    break;
6018bb01a1efSYegappan Lakshmanan 		}
6019bb01a1efSYegappan Lakshmanan 		found_match = TRUE;
6020bb01a1efSYegappan Lakshmanan 		if (--*tomatch == 0)
6021bb01a1efSYegappan Lakshmanan 		    break;
6022bb01a1efSYegappan Lakshmanan 		if ((flags & VGR_GLOBAL) == 0)
6023bb01a1efSYegappan Lakshmanan 		    break;
6024bb01a1efSYegappan Lakshmanan 		col = matches[pat_len - 1] + col + 1;
6025bb01a1efSYegappan Lakshmanan 		if (col > (colnr_T)STRLEN(str))
6026bb01a1efSYegappan Lakshmanan 		    break;
6027bb01a1efSYegappan Lakshmanan 	    }
6028bb01a1efSYegappan Lakshmanan 	}
602975b0a888SBram Moolenaar 	line_breakcheck();
603075b0a888SBram Moolenaar 	if (got_int)
603175b0a888SBram Moolenaar 	    break;
603275b0a888SBram Moolenaar     }
603375b0a888SBram Moolenaar 
603475b0a888SBram Moolenaar     return found_match;
603575b0a888SBram Moolenaar }
603675b0a888SBram Moolenaar 
603775b0a888SBram Moolenaar /*
603875b0a888SBram Moolenaar  * Jump to the first match and update the directory.
603975b0a888SBram Moolenaar  */
604075b0a888SBram Moolenaar     static void
vgr_jump_to_match(qf_info_T * qi,int forceit,int * redraw_for_dummy,buf_T * first_match_buf,char_u * target_dir)604175b0a888SBram Moolenaar vgr_jump_to_match(
604275b0a888SBram Moolenaar 	qf_info_T   *qi,
604375b0a888SBram Moolenaar 	int	    forceit,
604475b0a888SBram Moolenaar 	int	    *redraw_for_dummy,
604575b0a888SBram Moolenaar 	buf_T	    *first_match_buf,
604675b0a888SBram Moolenaar 	char_u	    *target_dir)
604775b0a888SBram Moolenaar {
604875b0a888SBram Moolenaar     buf_T	*buf;
604975b0a888SBram Moolenaar 
605075b0a888SBram Moolenaar     buf = curbuf;
605175b0a888SBram Moolenaar     qf_jump(qi, 0, 0, forceit);
605275b0a888SBram Moolenaar     if (buf != curbuf)
605300bf8cd2SBram Moolenaar 	// If we jumped to another buffer redrawing will already be
605400bf8cd2SBram Moolenaar 	// taken care of.
605575b0a888SBram Moolenaar 	*redraw_for_dummy = FALSE;
605675b0a888SBram Moolenaar 
605700bf8cd2SBram Moolenaar     // Jump to the directory used after loading the buffer.
605875b0a888SBram Moolenaar     if (curbuf == first_match_buf && target_dir != NULL)
605975b0a888SBram Moolenaar     {
606075b0a888SBram Moolenaar 	exarg_T ea;
606175b0a888SBram Moolenaar 
6062a80faa89SBram Moolenaar 	CLEAR_FIELD(ea);
606375b0a888SBram Moolenaar 	ea.arg = target_dir;
606475b0a888SBram Moolenaar 	ea.cmdidx = CMD_lcd;
606575b0a888SBram Moolenaar 	ex_cd(&ea);
606675b0a888SBram Moolenaar     }
606775b0a888SBram Moolenaar }
606875b0a888SBram Moolenaar 
606975b0a888SBram Moolenaar /*
6070d6a98a3aSBram Moolenaar  * :vimgrep command arguments
607186b68359SBram Moolenaar  */
6072d6a98a3aSBram Moolenaar typedef struct
607386b68359SBram Moolenaar {
6074d6a98a3aSBram Moolenaar     long	tomatch;	// maximum number of matches to find
6075d6a98a3aSBram Moolenaar     char_u	*spat;		// search pattern
6076d6a98a3aSBram Moolenaar     int		flags;		// search modifier
6077d6a98a3aSBram Moolenaar     char_u	**fnames;	// list of files to search
6078d6a98a3aSBram Moolenaar     int		fcount;		// number of files
6079d6a98a3aSBram Moolenaar     regmmatch_T	regmatch;	// compiled search pattern
6080d6a98a3aSBram Moolenaar     char_u	*qf_title;	// quickfix list title
6081d6a98a3aSBram Moolenaar } vgr_args_T;
6082d6a98a3aSBram Moolenaar 
6083d6a98a3aSBram Moolenaar /*
6084d6a98a3aSBram Moolenaar  * Process :vimgrep command arguments. The command syntax is:
6085d6a98a3aSBram Moolenaar  *
6086d6a98a3aSBram Moolenaar  *	:{count}vimgrep /{pattern}/[g][j] {file} ...
6087d6a98a3aSBram Moolenaar  */
6088d6a98a3aSBram Moolenaar     static int
vgr_process_args(exarg_T * eap,vgr_args_T * args)6089d6a98a3aSBram Moolenaar vgr_process_args(
6090d6a98a3aSBram Moolenaar 	exarg_T		*eap,
6091d6a98a3aSBram Moolenaar 	vgr_args_T	*args)
6092d6a98a3aSBram Moolenaar {
609386b68359SBram Moolenaar     char_u	*p;
60947c62692dSBram Moolenaar 
6095d6a98a3aSBram Moolenaar     vim_memset(args, 0, sizeof(*args));
609686b68359SBram Moolenaar 
6097d6a98a3aSBram Moolenaar     args->regmatch.regprog = NULL;
6098d6a98a3aSBram Moolenaar     args->qf_title = vim_strsave(qf_cmdtitle(*eap->cmdlinep));
6099a6557605SBram Moolenaar 
61001f35bf9cSBram Moolenaar     if (eap->addr_count > 0)
6101d6a98a3aSBram Moolenaar 	args->tomatch = eap->line2;
61021f35bf9cSBram Moolenaar     else
6103d6a98a3aSBram Moolenaar 	args->tomatch = MAXLNUM;
61041f35bf9cSBram Moolenaar 
610500bf8cd2SBram Moolenaar     // Get the search pattern: either white-separated or enclosed in //
6106d6a98a3aSBram Moolenaar     p = skip_vimgrep_pat(eap->arg, &args->spat, &args->flags);
6107748bf037SBram Moolenaar     if (p == NULL)
610886b68359SBram Moolenaar     {
6109f9e3e09fSBram Moolenaar 	emsg(_(e_invalpat));
6110d6a98a3aSBram Moolenaar 	return FAIL;
611186b68359SBram Moolenaar     }
611260abe753SBram Moolenaar 
6113d6a98a3aSBram Moolenaar     vgr_init_regmatch(&args->regmatch, args->spat);
6114d6a98a3aSBram Moolenaar     if (args->regmatch.regprog == NULL)
6115d6a98a3aSBram Moolenaar 	return FAIL;
611686b68359SBram Moolenaar 
611786b68359SBram Moolenaar     p = skipwhite(p);
611886b68359SBram Moolenaar     if (*p == NUL)
611986b68359SBram Moolenaar     {
6120f9e3e09fSBram Moolenaar 	emsg(_("E683: File name missing or invalid pattern"));
6121d6a98a3aSBram Moolenaar 	return FAIL;
612286b68359SBram Moolenaar     }
612386b68359SBram Moolenaar 
6124f8c6a171SBram Moolenaar     // Parse the list of arguments, wildcards have already been expanded.
6125d6a98a3aSBram Moolenaar     if (get_arglist_exp(p, &args->fcount, &args->fnames, TRUE) == FAIL)
6126d6a98a3aSBram Moolenaar 	return FAIL;
6127d6a98a3aSBram Moolenaar     if (args->fcount == 0)
612886b68359SBram Moolenaar     {
6129f9e3e09fSBram Moolenaar 	emsg(_(e_nomatch));
6130d6a98a3aSBram Moolenaar 	return FAIL;
613186b68359SBram Moolenaar     }
613286b68359SBram Moolenaar 
6133d6a98a3aSBram Moolenaar     return OK;
6134d6a98a3aSBram Moolenaar }
6135d6a98a3aSBram Moolenaar 
6136d6a98a3aSBram Moolenaar /*
61378ce4b7edSBram Moolenaar  * Return TRUE if "buf" had an existing swap file, the current swap file does
61388ce4b7edSBram Moolenaar  * not end in ".swp".
61398ce4b7edSBram Moolenaar  */
61408ce4b7edSBram Moolenaar     static int
existing_swapfile(buf_T * buf)61418ce4b7edSBram Moolenaar existing_swapfile(buf_T *buf)
61428ce4b7edSBram Moolenaar {
6143997cd1a1SBram Moolenaar     if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL)
61448ce4b7edSBram Moolenaar     {
61458ce4b7edSBram Moolenaar 	char_u *fname = buf->b_ml.ml_mfp->mf_fname;
61468ce4b7edSBram Moolenaar 	size_t len = STRLEN(fname);
61478ce4b7edSBram Moolenaar 
61488ce4b7edSBram Moolenaar 	return fname[len - 1] != 'p' || fname[len - 2] != 'w';
61498ce4b7edSBram Moolenaar     }
61508ce4b7edSBram Moolenaar     return FALSE;
61518ce4b7edSBram Moolenaar }
61528ce4b7edSBram Moolenaar 
61538ce4b7edSBram Moolenaar /*
6154d6a98a3aSBram Moolenaar  * Search for a pattern in a list of files and populate the quickfix list with
6155d6a98a3aSBram Moolenaar  * the matches.
6156d6a98a3aSBram Moolenaar  */
6157d6a98a3aSBram Moolenaar     static int
vgr_process_files(win_T * wp,qf_info_T * qi,vgr_args_T * cmd_args,int * redraw_for_dummy,buf_T ** first_match_buf,char_u ** target_dir)6158d6a98a3aSBram Moolenaar vgr_process_files(
6159d6a98a3aSBram Moolenaar 	win_T		*wp,
6160d6a98a3aSBram Moolenaar 	qf_info_T	*qi,
6161d6a98a3aSBram Moolenaar 	vgr_args_T	*cmd_args,
6162d6a98a3aSBram Moolenaar 	int		*redraw_for_dummy,
6163d6a98a3aSBram Moolenaar 	buf_T		**first_match_buf,
6164d6a98a3aSBram Moolenaar 	char_u		**target_dir)
6165d6a98a3aSBram Moolenaar {
6166d6a98a3aSBram Moolenaar     int		status = FAIL;
6167d6a98a3aSBram Moolenaar     int_u	save_qfid = qf_get_curlist(qi)->qf_id;
6168d6a98a3aSBram Moolenaar     time_t	seconds = 0;
6169d6a98a3aSBram Moolenaar     char_u	*fname;
6170d6a98a3aSBram Moolenaar     int		fi;
6171d6a98a3aSBram Moolenaar     buf_T	*buf;
6172d6a98a3aSBram Moolenaar     int		duplicate_name = FALSE;
6173d6a98a3aSBram Moolenaar     int		using_dummy;
6174d6a98a3aSBram Moolenaar     char_u	*dirname_start = NULL;
6175d6a98a3aSBram Moolenaar     char_u	*dirname_now = NULL;
6176d6a98a3aSBram Moolenaar     int		found_match;
6177d6a98a3aSBram Moolenaar     aco_save_T	aco;
6178d6a98a3aSBram Moolenaar 
6179b86a3432SBram Moolenaar     dirname_start = alloc_id(MAXPATHL, aid_qf_dirname_start);
6180b86a3432SBram Moolenaar     dirname_now = alloc_id(MAXPATHL, aid_qf_dirname_now);
6181d9462e39SBram Moolenaar     if (dirname_start == NULL || dirname_now == NULL)
6182d9462e39SBram Moolenaar 	goto theend;
6183d9462e39SBram Moolenaar 
618400bf8cd2SBram Moolenaar     // Remember the current directory, because a BufRead autocommand that does
618500bf8cd2SBram Moolenaar     // ":lcd %:p:h" changes the meaning of short path names.
6186d089d9b3SBram Moolenaar     mch_dirname(dirname_start, MAXPATHL);
6187d089d9b3SBram Moolenaar 
6188dcaf10e1SBram Moolenaar     seconds = (time_t)0;
6189d6a98a3aSBram Moolenaar     for (fi = 0; fi < cmd_args->fcount && !got_int && cmd_args->tomatch > 0;
6190d6a98a3aSBram Moolenaar 									++fi)
619186b68359SBram Moolenaar     {
6192d6a98a3aSBram Moolenaar 	fname = shorten_fname1(cmd_args->fnames[fi]);
6193dcaf10e1SBram Moolenaar 	if (time(NULL) > seconds)
6194dcaf10e1SBram Moolenaar 	{
619500bf8cd2SBram Moolenaar 	    // Display the file name every second or so, show the user we are
619600bf8cd2SBram Moolenaar 	    // working on it.
6197dcaf10e1SBram Moolenaar 	    seconds = time(NULL);
619875b0a888SBram Moolenaar 	    vgr_display_fname(fname);
6199dcaf10e1SBram Moolenaar 	}
6200dcaf10e1SBram Moolenaar 
6201d6a98a3aSBram Moolenaar 	buf = buflist_findname_exp(cmd_args->fnames[fi]);
620281695250SBram Moolenaar 	if (buf == NULL || buf->b_ml.ml_mfp == NULL)
620381695250SBram Moolenaar 	{
620400bf8cd2SBram Moolenaar 	    // Remember that a buffer with this name already exists.
620581695250SBram Moolenaar 	    duplicate_name = (buf != NULL);
6206dcaf10e1SBram Moolenaar 	    using_dummy = TRUE;
6207d6a98a3aSBram Moolenaar 	    *redraw_for_dummy = TRUE;
6208dcaf10e1SBram Moolenaar 
620975b0a888SBram Moolenaar 	    buf = vgr_load_dummy_buf(fname, dirname_start, dirname_now);
621081695250SBram Moolenaar 	}
621181695250SBram Moolenaar 	else
621200bf8cd2SBram Moolenaar 	    // Use existing, loaded buffer.
621381695250SBram Moolenaar 	    using_dummy = FALSE;
6214dcaf10e1SBram Moolenaar 
621500bf8cd2SBram Moolenaar 	// Check whether the quickfix list is still valid. When loading a
621600bf8cd2SBram Moolenaar 	// buffer above, autocommands might have changed the quickfix list.
6217d6a98a3aSBram Moolenaar 	if (!vgr_qflist_valid(wp, qi, save_qfid, cmd_args->qf_title))
62183c097226SBram Moolenaar 	    goto theend;
6219d6a98a3aSBram Moolenaar 
62204aa47b28SBram Moolenaar 	save_qfid = qf_get_curlist(qi)->qf_id;
6221321a9ec6SBram Moolenaar 
622281695250SBram Moolenaar 	if (buf == NULL)
6223dcaf10e1SBram Moolenaar 	{
6224dcaf10e1SBram Moolenaar 	    if (!got_int)
6225f9e3e09fSBram Moolenaar 		smsg(_("Cannot open file \"%s\""), fname);
6226dcaf10e1SBram Moolenaar 	}
622786b68359SBram Moolenaar 	else
622886b68359SBram Moolenaar 	{
622900bf8cd2SBram Moolenaar 	    // Try for a match in all lines of the buffer.
623000bf8cd2SBram Moolenaar 	    // For ":1vimgrep" look for first match only.
62319afe5e9cSBram Moolenaar 	    found_match = vgr_match_buflines(qf_get_curlist(qi),
6232bb01a1efSYegappan Lakshmanan 		    fname, buf, cmd_args->spat, &cmd_args->regmatch,
6233d6a98a3aSBram Moolenaar 		    &cmd_args->tomatch, duplicate_name, cmd_args->flags);
623475b0a888SBram Moolenaar 
623581695250SBram Moolenaar 	    if (using_dummy)
623681695250SBram Moolenaar 	    {
6237d6a98a3aSBram Moolenaar 		if (found_match && *first_match_buf == NULL)
6238d6a98a3aSBram Moolenaar 		    *first_match_buf = buf;
623981695250SBram Moolenaar 		if (duplicate_name)
6240dcaf10e1SBram Moolenaar 		{
624100bf8cd2SBram Moolenaar 		    // Never keep a dummy buffer if there is another buffer
624200bf8cd2SBram Moolenaar 		    // with the same name.
62437f51a82cSBram Moolenaar 		    wipe_dummy_buffer(buf, dirname_start);
6244dcaf10e1SBram Moolenaar 		    buf = NULL;
6245dcaf10e1SBram Moolenaar 		}
6246e1004401SBram Moolenaar 		else if ((cmdmod.cmod_flags & CMOD_HIDE) == 0
624700bf8cd2SBram Moolenaar 			    || buf->b_p_bh[0] == 'u'	// "unload"
624800bf8cd2SBram Moolenaar 			    || buf->b_p_bh[0] == 'w'	// "wipe"
624900bf8cd2SBram Moolenaar 			    || buf->b_p_bh[0] == 'd')	// "delete"
625081695250SBram Moolenaar 		{
625100bf8cd2SBram Moolenaar 		    // When no match was found we don't need to remember the
625200bf8cd2SBram Moolenaar 		    // buffer, wipe it out.  If there was a match and it
625300bf8cd2SBram Moolenaar 		    // wasn't the first one or we won't jump there: only
625400bf8cd2SBram Moolenaar 		    // unload the buffer.
625500bf8cd2SBram Moolenaar 		    // Ignore 'hidden' here, because it may lead to having too
625600bf8cd2SBram Moolenaar 		    // many swap files.
625781695250SBram Moolenaar 		    if (!found_match)
6258dcaf10e1SBram Moolenaar 		    {
62597f51a82cSBram Moolenaar 			wipe_dummy_buffer(buf, dirname_start);
6260dcaf10e1SBram Moolenaar 			buf = NULL;
6261dcaf10e1SBram Moolenaar 		    }
6262d6a98a3aSBram Moolenaar 		    else if (buf != *first_match_buf
62638ce4b7edSBram Moolenaar 					|| (cmd_args->flags & VGR_NOJUMP)
62648ce4b7edSBram Moolenaar 					|| existing_swapfile(buf))
6265dcaf10e1SBram Moolenaar 		    {
62667f51a82cSBram Moolenaar 			unload_dummy_buffer(buf, dirname_start);
626700bf8cd2SBram Moolenaar 			// Keeping the buffer, remove the dummy flag.
6268015102e9SBram Moolenaar 			buf->b_flags &= ~BF_DUMMY;
6269dcaf10e1SBram Moolenaar 			buf = NULL;
627081695250SBram Moolenaar 		    }
627181695250SBram Moolenaar 		}
6272dcaf10e1SBram Moolenaar 
6273dcaf10e1SBram Moolenaar 		if (buf != NULL)
6274dcaf10e1SBram Moolenaar 		{
627500bf8cd2SBram Moolenaar 		    // Keeping the buffer, remove the dummy flag.
6276015102e9SBram Moolenaar 		    buf->b_flags &= ~BF_DUMMY;
6277015102e9SBram Moolenaar 
627800bf8cd2SBram Moolenaar 		    // If the buffer is still loaded we need to use the
627900bf8cd2SBram Moolenaar 		    // directory we jumped to below.
6280d6a98a3aSBram Moolenaar 		    if (buf == *first_match_buf
6281d6a98a3aSBram Moolenaar 			    && *target_dir == NULL
6282d089d9b3SBram Moolenaar 			    && STRCMP(dirname_start, dirname_now) != 0)
6283d6a98a3aSBram Moolenaar 			*target_dir = vim_strsave(dirname_now);
6284d089d9b3SBram Moolenaar 
628500bf8cd2SBram Moolenaar 		    // The buffer is still loaded, the Filetype autocommands
628600bf8cd2SBram Moolenaar 		    // need to be done now, in that buffer.  And the modelines
628700bf8cd2SBram Moolenaar 		    // need to be done (again).  But not the window-local
628800bf8cd2SBram Moolenaar 		    // options!
6289dcaf10e1SBram Moolenaar 		    aucmd_prepbuf(&aco, buf);
6290f2bd8ef2SBram Moolenaar #if defined(FEAT_SYN_HL)
6291dcaf10e1SBram Moolenaar 		    apply_autocmds(EVENT_FILETYPE, buf->b_p_ft,
6292dcaf10e1SBram Moolenaar 						     buf->b_fname, TRUE, buf);
6293dcaf10e1SBram Moolenaar #endif
6294a3227e2bSBram Moolenaar 		    do_modelines(OPT_NOWIN);
6295faa959a8SBram Moolenaar 		    aucmd_restbuf(&aco);
6296faa959a8SBram Moolenaar 		}
6297dcaf10e1SBram Moolenaar 	    }
629886b68359SBram Moolenaar 	}
629986b68359SBram Moolenaar     }
630086b68359SBram Moolenaar 
6301d6a98a3aSBram Moolenaar     status = OK;
6302d6a98a3aSBram Moolenaar 
6303d6a98a3aSBram Moolenaar theend:
6304d6a98a3aSBram Moolenaar     vim_free(dirname_now);
6305d6a98a3aSBram Moolenaar     vim_free(dirname_start);
6306d6a98a3aSBram Moolenaar     return status;
6307d6a98a3aSBram Moolenaar }
6308d6a98a3aSBram Moolenaar 
6309d6a98a3aSBram Moolenaar /*
6310d6a98a3aSBram Moolenaar  * ":vimgrep {pattern} file(s)"
6311d6a98a3aSBram Moolenaar  * ":vimgrepadd {pattern} file(s)"
6312d6a98a3aSBram Moolenaar  * ":lvimgrep {pattern} file(s)"
6313d6a98a3aSBram Moolenaar  * ":lvimgrepadd {pattern} file(s)"
6314d6a98a3aSBram Moolenaar  */
6315d6a98a3aSBram Moolenaar     void
ex_vimgrep(exarg_T * eap)6316d6a98a3aSBram Moolenaar ex_vimgrep(exarg_T *eap)
6317d6a98a3aSBram Moolenaar {
6318d6a98a3aSBram Moolenaar     vgr_args_T	args;
6319d6a98a3aSBram Moolenaar     qf_info_T	*qi;
6320d6a98a3aSBram Moolenaar     qf_list_T	*qfl;
6321d6a98a3aSBram Moolenaar     int_u	save_qfid;
6322d6a98a3aSBram Moolenaar     win_T	*wp = NULL;
6323d6a98a3aSBram Moolenaar     int		redraw_for_dummy = FALSE;
6324d6a98a3aSBram Moolenaar     buf_T	*first_match_buf = NULL;
6325d6a98a3aSBram Moolenaar     char_u	*target_dir = NULL;
6326d6a98a3aSBram Moolenaar     char_u	*au_name =  NULL;
6327d6a98a3aSBram Moolenaar     int		status;
6328d6a98a3aSBram Moolenaar 
6329d6a98a3aSBram Moolenaar     au_name = vgr_get_auname(eap->cmdidx);
6330d6a98a3aSBram Moolenaar     if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
6331d6a98a3aSBram Moolenaar 					       curbuf->b_fname, TRUE, curbuf))
6332d6a98a3aSBram Moolenaar     {
6333d6a98a3aSBram Moolenaar #ifdef FEAT_EVAL
6334d6a98a3aSBram Moolenaar 	if (aborting())
6335d6a98a3aSBram Moolenaar 	    return;
6336d6a98a3aSBram Moolenaar #endif
6337d6a98a3aSBram Moolenaar     }
6338d6a98a3aSBram Moolenaar 
6339d6a98a3aSBram Moolenaar     qi = qf_cmd_get_or_alloc_stack(eap, &wp);
6340d6a98a3aSBram Moolenaar     if (qi == NULL)
6341d6a98a3aSBram Moolenaar 	return;
6342d6a98a3aSBram Moolenaar 
6343d6a98a3aSBram Moolenaar     if (vgr_process_args(eap, &args) == FAIL)
6344d6a98a3aSBram Moolenaar 	goto theend;
6345d6a98a3aSBram Moolenaar 
6346d6a98a3aSBram Moolenaar     if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd
6347d6a98a3aSBram Moolenaar 		&& eap->cmdidx != CMD_vimgrepadd
6348d6a98a3aSBram Moolenaar 		&& eap->cmdidx != CMD_lvimgrepadd)
6349d6a98a3aSBram Moolenaar 					|| qf_stack_empty(qi))
6350d6a98a3aSBram Moolenaar 	// make place for a new list
6351d6a98a3aSBram Moolenaar 	qf_new_list(qi, args.qf_title);
6352d6a98a3aSBram Moolenaar 
6353d6a98a3aSBram Moolenaar     incr_quickfix_busy();
6354d6a98a3aSBram Moolenaar 
6355d6a98a3aSBram Moolenaar     status = vgr_process_files(wp, qi, &args, &redraw_for_dummy,
6356d6a98a3aSBram Moolenaar 						&first_match_buf, &target_dir);
6357d6a98a3aSBram Moolenaar     if (status != OK)
6358d6a98a3aSBram Moolenaar     {
6359d6a98a3aSBram Moolenaar 	FreeWild(args.fcount, args.fnames);
6360d6a98a3aSBram Moolenaar 	decr_quickfix_busy();
6361d6a98a3aSBram Moolenaar 	goto theend;
6362d6a98a3aSBram Moolenaar     }
6363d6a98a3aSBram Moolenaar 
6364d6a98a3aSBram Moolenaar     FreeWild(args.fcount, args.fnames);
636586b68359SBram Moolenaar 
63664aa47b28SBram Moolenaar     qfl = qf_get_curlist(qi);
6367108e7b42SBram Moolenaar     qfl->qf_nonevalid = FALSE;
6368108e7b42SBram Moolenaar     qfl->qf_ptr = qfl->qf_start;
6369108e7b42SBram Moolenaar     qfl->qf_index = 1;
6370108e7b42SBram Moolenaar     qf_list_changed(qfl);
637186b68359SBram Moolenaar 
6372864293abSBram Moolenaar     qf_update_buffer(qi, NULL);
637386b68359SBram Moolenaar 
6374d6a98a3aSBram Moolenaar     // Remember the current quickfix list identifier, so that we can check for
6375d6a98a3aSBram Moolenaar     // autocommands changing the current quickfix list.
6376d6a98a3aSBram Moolenaar     save_qfid = qf_get_curlist(qi)->qf_id;
6377d6a98a3aSBram Moolenaar 
6378f9393ef5SBram Moolenaar     if (au_name != NULL)
6379f9393ef5SBram Moolenaar 	apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
6380f9393ef5SBram Moolenaar 					       curbuf->b_fname, TRUE, curbuf);
638100bf8cd2SBram Moolenaar     // The QuickFixCmdPost autocmd may free the quickfix list. Check the list
638200bf8cd2SBram Moolenaar     // is still valid.
63839f84ded3SBram Moolenaar     if (!qflist_valid(wp, save_qfid)
63849f84ded3SBram Moolenaar 	    || qf_restore_list(qi, save_qfid) == FAIL)
63859f84ded3SBram Moolenaar     {
63869f84ded3SBram Moolenaar 	decr_quickfix_busy();
63873c097226SBram Moolenaar 	goto theend;
63889f84ded3SBram Moolenaar     }
6389531b9a3aSBram Moolenaar 
6390c631f2dfSBram Moolenaar     // Jump to first match.
63910398e00aSBram Moolenaar     if (!qf_list_empty(qf_get_curlist(qi)))
639205159a0cSBram Moolenaar     {
6393d6a98a3aSBram Moolenaar 	if ((args.flags & VGR_NOJUMP) == 0)
639475b0a888SBram Moolenaar 	    vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy,
639575b0a888SBram Moolenaar 		    first_match_buf, target_dir);
639605159a0cSBram Moolenaar     }
639781695250SBram Moolenaar     else
6398d6a98a3aSBram Moolenaar 	semsg(_(e_nomatch2), args.spat);
639986b68359SBram Moolenaar 
64009f84ded3SBram Moolenaar     decr_quickfix_busy();
64019f84ded3SBram Moolenaar 
640200bf8cd2SBram Moolenaar     // If we loaded a dummy buffer into the current window, the autocommands
640300bf8cd2SBram Moolenaar     // may have messed up things, need to redraw and recompute folds.
64041042fa38SBram Moolenaar     if (redraw_for_dummy)
64051042fa38SBram Moolenaar     {
64061042fa38SBram Moolenaar #ifdef FEAT_FOLDING
64071042fa38SBram Moolenaar 	foldUpdateAll(curwin);
64081042fa38SBram Moolenaar #else
64091042fa38SBram Moolenaar 	redraw_later(NOT_VALID);
64101042fa38SBram Moolenaar #endif
64111042fa38SBram Moolenaar     }
64121042fa38SBram Moolenaar 
641386b68359SBram Moolenaar theend:
6414d6a98a3aSBram Moolenaar     vim_free(args.qf_title);
6415d089d9b3SBram Moolenaar     vim_free(target_dir);
6416d6a98a3aSBram Moolenaar     vim_regfree(args.regmatch.regprog);
641786b68359SBram Moolenaar }
641886b68359SBram Moolenaar 
641986b68359SBram Moolenaar /*
64207f51a82cSBram Moolenaar  * Restore current working directory to "dirname_start" if they differ, taking
64217f51a82cSBram Moolenaar  * into account whether it is set locally or globally.
64227f51a82cSBram Moolenaar  */
64237f51a82cSBram Moolenaar     static void
restore_start_dir(char_u * dirname_start)642405540976SBram Moolenaar restore_start_dir(char_u *dirname_start)
64257f51a82cSBram Moolenaar {
64267f51a82cSBram Moolenaar     char_u *dirname_now = alloc(MAXPATHL);
64277f51a82cSBram Moolenaar 
64287f51a82cSBram Moolenaar     if (NULL != dirname_now)
64297f51a82cSBram Moolenaar     {
64307f51a82cSBram Moolenaar 	mch_dirname(dirname_now, MAXPATHL);
64317f51a82cSBram Moolenaar 	if (STRCMP(dirname_start, dirname_now) != 0)
64327f51a82cSBram Moolenaar 	{
643300bf8cd2SBram Moolenaar 	    // If the directory has changed, change it back by building up an
643400bf8cd2SBram Moolenaar 	    // appropriate ex command and executing it.
64357f51a82cSBram Moolenaar 	    exarg_T ea;
64367f51a82cSBram Moolenaar 
6437a80faa89SBram Moolenaar 	    CLEAR_FIELD(ea);
64387f51a82cSBram Moolenaar 	    ea.arg = dirname_start;
64397f51a82cSBram Moolenaar 	    ea.cmdidx = (curwin->w_localdir == NULL) ? CMD_cd : CMD_lcd;
64407f51a82cSBram Moolenaar 	    ex_cd(&ea);
64417f51a82cSBram Moolenaar 	}
6442f135435fSBram Moolenaar 	vim_free(dirname_now);
64437f51a82cSBram Moolenaar     }
64447f51a82cSBram Moolenaar }
64457f51a82cSBram Moolenaar 
64467f51a82cSBram Moolenaar /*
64477f51a82cSBram Moolenaar  * Load file "fname" into a dummy buffer and return the buffer pointer,
64487f51a82cSBram Moolenaar  * placing the directory resulting from the buffer load into the
64497f51a82cSBram Moolenaar  * "resulting_dir" pointer. "resulting_dir" must be allocated by the caller
64507f51a82cSBram Moolenaar  * prior to calling this function. Restores directory to "dirname_start" prior
64517f51a82cSBram Moolenaar  * to returning, if autocmds or the 'autochdir' option have changed it.
64527f51a82cSBram Moolenaar  *
64537f51a82cSBram Moolenaar  * If creating the dummy buffer does not fail, must call unload_dummy_buffer()
64547f51a82cSBram Moolenaar  * or wipe_dummy_buffer() later!
64557f51a82cSBram Moolenaar  *
645681695250SBram Moolenaar  * Returns NULL if it fails.
645781695250SBram Moolenaar  */
645881695250SBram Moolenaar     static buf_T *
load_dummy_buffer(char_u * fname,char_u * dirname_start,char_u * resulting_dir)645905540976SBram Moolenaar load_dummy_buffer(
646005540976SBram Moolenaar     char_u	*fname,
646100bf8cd2SBram Moolenaar     char_u	*dirname_start,  // in: old directory
646200bf8cd2SBram Moolenaar     char_u	*resulting_dir)  // out: new directory
646381695250SBram Moolenaar {
646481695250SBram Moolenaar     buf_T	*newbuf;
64657c0a2f36SBram Moolenaar     bufref_T	newbufref;
64667c0a2f36SBram Moolenaar     bufref_T	newbuf_to_wipe;
646781695250SBram Moolenaar     int		failed = TRUE;
646881695250SBram Moolenaar     aco_save_T	aco;
64694fb921e3SBram Moolenaar     int		readfile_result;
647081695250SBram Moolenaar 
647100bf8cd2SBram Moolenaar     // Allocate a buffer without putting it in the buffer list.
647281695250SBram Moolenaar     newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
647381695250SBram Moolenaar     if (newbuf == NULL)
647481695250SBram Moolenaar 	return NULL;
64757c0a2f36SBram Moolenaar     set_bufref(&newbufref, newbuf);
647681695250SBram Moolenaar 
647700bf8cd2SBram Moolenaar     // Init the options.
64788cd06cabSBram Moolenaar     buf_copy_options(newbuf, BCO_ENTER | BCO_NOHELP);
64798cd06cabSBram Moolenaar 
648000bf8cd2SBram Moolenaar     // need to open the memfile before putting the buffer in a window
6481f061e0beSBram Moolenaar     if (ml_open(newbuf) == OK)
6482f061e0beSBram Moolenaar     {
648300bf8cd2SBram Moolenaar 	// Make sure this buffer isn't wiped out by autocommands.
64844fb921e3SBram Moolenaar 	++newbuf->b_locked;
64854fb921e3SBram Moolenaar 
648600bf8cd2SBram Moolenaar 	// set curwin/curbuf to buf and save a few things
648781695250SBram Moolenaar 	aucmd_prepbuf(&aco, newbuf);
648881695250SBram Moolenaar 
648900bf8cd2SBram Moolenaar 	// Need to set the filename for autocommands.
649081695250SBram Moolenaar 	(void)setfname(curbuf, fname, NULL, FALSE);
649181695250SBram Moolenaar 
649200bf8cd2SBram Moolenaar 	// Create swap file now to avoid the ATTENTION message.
649381695250SBram Moolenaar 	check_need_swap(TRUE);
649481695250SBram Moolenaar 
649500bf8cd2SBram Moolenaar 	// Remove the "dummy" flag, otherwise autocommands may not
649600bf8cd2SBram Moolenaar 	// work.
649781695250SBram Moolenaar 	curbuf->b_flags &= ~BF_DUMMY;
649881695250SBram Moolenaar 
64997c0a2f36SBram Moolenaar 	newbuf_to_wipe.br_buf = NULL;
65004fb921e3SBram Moolenaar 	readfile_result = readfile(fname, NULL,
650181695250SBram Moolenaar 		    (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
65024fb921e3SBram Moolenaar 		    NULL, READ_NEW | READ_DUMMY);
65034fb921e3SBram Moolenaar 	--newbuf->b_locked;
65044fb921e3SBram Moolenaar 	if (readfile_result == OK
6505d68071d8SBram Moolenaar 		&& !got_int
650681695250SBram Moolenaar 		&& !(curbuf->b_flags & BF_NEW))
650781695250SBram Moolenaar 	{
650881695250SBram Moolenaar 	    failed = FALSE;
650981695250SBram Moolenaar 	    if (curbuf != newbuf)
651081695250SBram Moolenaar 	    {
651100bf8cd2SBram Moolenaar 		// Bloody autocommands changed the buffer!  Can happen when
651200bf8cd2SBram Moolenaar 		// using netrw and editing a remote file.  Use the current
651300bf8cd2SBram Moolenaar 		// buffer instead, delete the dummy one after restoring the
651400bf8cd2SBram Moolenaar 		// window stuff.
65157c0a2f36SBram Moolenaar 		set_bufref(&newbuf_to_wipe, newbuf);
651681695250SBram Moolenaar 		newbuf = curbuf;
651781695250SBram Moolenaar 	    }
651881695250SBram Moolenaar 	}
651981695250SBram Moolenaar 
652000bf8cd2SBram Moolenaar 	// restore curwin/curbuf and a few other things
652181695250SBram Moolenaar 	aucmd_restbuf(&aco);
65227c0a2f36SBram Moolenaar 	if (newbuf_to_wipe.br_buf != NULL && bufref_valid(&newbuf_to_wipe))
65237c0a2f36SBram Moolenaar 	    wipe_buffer(newbuf_to_wipe.br_buf, FALSE);
6524ea3f2e7bSBram Moolenaar 
652500bf8cd2SBram Moolenaar 	// Add back the "dummy" flag, otherwise buflist_findname_stat() won't
652600bf8cd2SBram Moolenaar 	// skip it.
6527ea3f2e7bSBram Moolenaar 	newbuf->b_flags |= BF_DUMMY;
6528f061e0beSBram Moolenaar     }
652981695250SBram Moolenaar 
653000bf8cd2SBram Moolenaar     // When autocommands/'autochdir' option changed directory: go back.
653100bf8cd2SBram Moolenaar     // Let the caller know what the resulting dir was first, in case it is
653200bf8cd2SBram Moolenaar     // important.
65337f51a82cSBram Moolenaar     mch_dirname(resulting_dir, MAXPATHL);
65347f51a82cSBram Moolenaar     restore_start_dir(dirname_start);
65357f51a82cSBram Moolenaar 
65367c0a2f36SBram Moolenaar     if (!bufref_valid(&newbufref))
653781695250SBram Moolenaar 	return NULL;
653881695250SBram Moolenaar     if (failed)
653981695250SBram Moolenaar     {
65407f51a82cSBram Moolenaar 	wipe_dummy_buffer(newbuf, dirname_start);
654181695250SBram Moolenaar 	return NULL;
654281695250SBram Moolenaar     }
654381695250SBram Moolenaar     return newbuf;
654481695250SBram Moolenaar }
654581695250SBram Moolenaar 
654681695250SBram Moolenaar /*
65477f51a82cSBram Moolenaar  * Wipe out the dummy buffer that load_dummy_buffer() created. Restores
65487f51a82cSBram Moolenaar  * directory to "dirname_start" prior to returning, if autocmds or the
65497f51a82cSBram Moolenaar  * 'autochdir' option have changed it.
655081695250SBram Moolenaar  */
655181695250SBram Moolenaar     static void
wipe_dummy_buffer(buf_T * buf,char_u * dirname_start)655205540976SBram Moolenaar wipe_dummy_buffer(buf_T *buf, char_u *dirname_start)
655381695250SBram Moolenaar {
65542573af35SBram Moolenaar     // If any autocommand opened a window on the dummy buffer, close that
65552573af35SBram Moolenaar     // window.  If we can't close them all then give up.
65562573af35SBram Moolenaar     while (buf->b_nwindows > 0)
65572573af35SBram Moolenaar     {
65582573af35SBram Moolenaar 	int	    did_one = FALSE;
65592573af35SBram Moolenaar 	win_T	    *wp;
65602573af35SBram Moolenaar 
65612573af35SBram Moolenaar 	if (firstwin->w_next != NULL)
656200d253e2SBram Moolenaar 	    FOR_ALL_WINDOWS(wp)
65632573af35SBram Moolenaar 		if (wp->w_buffer == buf)
65642573af35SBram Moolenaar 		{
65652573af35SBram Moolenaar 		    if (win_close(wp, FALSE) == OK)
65662573af35SBram Moolenaar 			did_one = TRUE;
65672573af35SBram Moolenaar 		    break;
65682573af35SBram Moolenaar 		}
65692573af35SBram Moolenaar 	if (!did_one)
65702573af35SBram Moolenaar 	    return;
65712573af35SBram Moolenaar     }
65722573af35SBram Moolenaar 
65732573af35SBram Moolenaar     if (curbuf != buf && buf->b_nwindows == 0)	// safety check
6574d68071d8SBram Moolenaar     {
6575f2bd8ef2SBram Moolenaar #if defined(FEAT_EVAL)
6576d68071d8SBram Moolenaar 	cleanup_T   cs;
6577d68071d8SBram Moolenaar 
657800bf8cd2SBram Moolenaar 	// Reset the error/interrupt/exception state here so that aborting()
657900bf8cd2SBram Moolenaar 	// returns FALSE when wiping out the buffer.  Otherwise it doesn't
658000bf8cd2SBram Moolenaar 	// work when got_int is set.
6581d68071d8SBram Moolenaar 	enter_cleanup(&cs);
6582d68071d8SBram Moolenaar #endif
6583d68071d8SBram Moolenaar 
65841cfb9bb5SBram Moolenaar 	wipe_buffer(buf, TRUE);
6585d68071d8SBram Moolenaar 
6586f2bd8ef2SBram Moolenaar #if defined(FEAT_EVAL)
658700bf8cd2SBram Moolenaar 	// Restore the error/interrupt/exception state if not discarded by a
658800bf8cd2SBram Moolenaar 	// new aborting error, interrupt, or uncaught exception.
6589d68071d8SBram Moolenaar 	leave_cleanup(&cs);
6590d68071d8SBram Moolenaar #endif
659100bf8cd2SBram Moolenaar 	// When autocommands/'autochdir' option changed directory: go back.
65927f51a82cSBram Moolenaar 	restore_start_dir(dirname_start);
6593d68071d8SBram Moolenaar     }
659481695250SBram Moolenaar }
659581695250SBram Moolenaar 
659681695250SBram Moolenaar /*
65977f51a82cSBram Moolenaar  * Unload the dummy buffer that load_dummy_buffer() created. Restores
65987f51a82cSBram Moolenaar  * directory to "dirname_start" prior to returning, if autocmds or the
65997f51a82cSBram Moolenaar  * 'autochdir' option have changed it.
660081695250SBram Moolenaar  */
660181695250SBram Moolenaar     static void
unload_dummy_buffer(buf_T * buf,char_u * dirname_start)660205540976SBram Moolenaar unload_dummy_buffer(buf_T *buf, char_u *dirname_start)
660381695250SBram Moolenaar {
660400bf8cd2SBram Moolenaar     if (curbuf != buf)		// safety check
66057f51a82cSBram Moolenaar     {
6606a6e8f888SBram Moolenaar 	close_buffer(NULL, buf, DOBUF_UNLOAD, FALSE, TRUE);
66077f51a82cSBram Moolenaar 
660800bf8cd2SBram Moolenaar 	// When autocommands/'autochdir' option changed directory: go back.
66097f51a82cSBram Moolenaar 	restore_start_dir(dirname_start);
66107f51a82cSBram Moolenaar     }
661181695250SBram Moolenaar }
661281695250SBram Moolenaar 
661305159a0cSBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
661405159a0cSBram Moolenaar /*
66154b96df5aSBram Moolenaar  * Copy the specified quickfix entry items into a new dict and append the dict
6616a16123a6SBram Moolenaar  * to 'list'.  Returns OK on success.
661705159a0cSBram Moolenaar  */
6618a16123a6SBram Moolenaar     static int
get_qfline_items(qfline_T * qfp,list_T * list)6619a16123a6SBram Moolenaar get_qfline_items(qfline_T *qfp, list_T *list)
662005159a0cSBram Moolenaar {
6621a16123a6SBram Moolenaar     int		bufnum;
662205159a0cSBram Moolenaar     dict_T	*dict;
662305159a0cSBram Moolenaar     char_u	buf[2];
662405159a0cSBram Moolenaar 
662500bf8cd2SBram Moolenaar     // Handle entries with a non-existing buffer number.
662648b66fb5SBram Moolenaar     bufnum = qfp->qf_fnum;
662748b66fb5SBram Moolenaar     if (bufnum != 0 && (buflist_findnr(bufnum) == NULL))
662848b66fb5SBram Moolenaar 	bufnum = 0;
662948b66fb5SBram Moolenaar 
663005159a0cSBram Moolenaar     if ((dict = dict_alloc()) == NULL)
663105159a0cSBram Moolenaar 	return FAIL;
663205159a0cSBram Moolenaar     if (list_append_dict(list, dict) == FAIL)
663305159a0cSBram Moolenaar 	return FAIL;
663405159a0cSBram Moolenaar 
663505159a0cSBram Moolenaar     buf[0] = qfp->qf_type;
663605159a0cSBram Moolenaar     buf[1] = NUL;
6637e0be167aSBram Moolenaar     if (dict_add_number(dict, "bufnr", (long)bufnum) == FAIL
6638e0be167aSBram Moolenaar 	    || dict_add_number(dict, "lnum",     (long)qfp->qf_lnum) == FAIL
66396864efa5Sthinca 	    || dict_add_number(dict, "end_lnum", (long)qfp->qf_end_lnum) == FAIL
6640e0be167aSBram Moolenaar 	    || dict_add_number(dict, "col",      (long)qfp->qf_col) == FAIL
66416864efa5Sthinca 	    || dict_add_number(dict, "end_col",  (long)qfp->qf_end_col) == FAIL
6642e0be167aSBram Moolenaar 	    || dict_add_number(dict, "vcol",     (long)qfp->qf_viscol) == FAIL
6643e0be167aSBram Moolenaar 	    || dict_add_number(dict, "nr",       (long)qfp->qf_nr) == FAIL
6644e0be167aSBram Moolenaar 	    || dict_add_string(dict, "module", qfp->qf_module) == FAIL
6645e0be167aSBram Moolenaar 	    || dict_add_string(dict, "pattern", qfp->qf_pattern) == FAIL
6646e0be167aSBram Moolenaar 	    || dict_add_string(dict, "text", qfp->qf_text) == FAIL
6647e0be167aSBram Moolenaar 	    || dict_add_string(dict, "type", buf) == FAIL
6648e0be167aSBram Moolenaar 	    || dict_add_number(dict, "valid", (long)qfp->qf_valid) == FAIL)
664905159a0cSBram Moolenaar 	return FAIL;
665005159a0cSBram Moolenaar 
6651a16123a6SBram Moolenaar     return OK;
665205159a0cSBram Moolenaar }
6653a16123a6SBram Moolenaar 
6654a16123a6SBram Moolenaar /*
6655a16123a6SBram Moolenaar  * Add each quickfix error to list "list" as a dictionary.
6656a16123a6SBram Moolenaar  * If qf_idx is -1, use the current list. Otherwise, use the specified list.
6657858ba06dSBram Moolenaar  * If eidx is not 0, then return only the specified entry. Otherwise return
6658858ba06dSBram Moolenaar  * all the entries.
6659a16123a6SBram Moolenaar  */
6660e677df8dSBram Moolenaar     static int
get_errorlist(qf_info_T * qi_arg,win_T * wp,int qf_idx,int eidx,list_T * list)6661858ba06dSBram Moolenaar get_errorlist(
6662858ba06dSBram Moolenaar 	qf_info_T	*qi_arg,
6663858ba06dSBram Moolenaar 	win_T		*wp,
6664858ba06dSBram Moolenaar 	int		qf_idx,
6665858ba06dSBram Moolenaar 	int		eidx,
6666858ba06dSBram Moolenaar 	list_T		*list)
6667a16123a6SBram Moolenaar {
6668a16123a6SBram Moolenaar     qf_info_T	*qi = qi_arg;
6669a16123a6SBram Moolenaar     qf_list_T	*qfl;
6670a16123a6SBram Moolenaar     qfline_T	*qfp;
6671a16123a6SBram Moolenaar     int		i;
6672a16123a6SBram Moolenaar 
6673a16123a6SBram Moolenaar     if (qi == NULL)
6674a16123a6SBram Moolenaar     {
6675a16123a6SBram Moolenaar 	qi = &ql_info;
6676a16123a6SBram Moolenaar 	if (wp != NULL)
6677a16123a6SBram Moolenaar 	{
6678a16123a6SBram Moolenaar 	    qi = GET_LOC_LIST(wp);
6679a16123a6SBram Moolenaar 	    if (qi == NULL)
6680a16123a6SBram Moolenaar 		return FAIL;
6681a16123a6SBram Moolenaar 	}
6682a16123a6SBram Moolenaar     }
6683a16123a6SBram Moolenaar 
6684858ba06dSBram Moolenaar     if (eidx < 0)
6685858ba06dSBram Moolenaar 	return OK;
6686858ba06dSBram Moolenaar 
6687a16123a6SBram Moolenaar     if (qf_idx == INVALID_QFIDX)
6688a16123a6SBram Moolenaar 	qf_idx = qi->qf_curlist;
6689a16123a6SBram Moolenaar 
6690a16123a6SBram Moolenaar     if (qf_idx >= qi->qf_listcount)
6691a16123a6SBram Moolenaar 	return FAIL;
6692a16123a6SBram Moolenaar 
6693a16123a6SBram Moolenaar     qfl = qf_get_list(qi, qf_idx);
6694a16123a6SBram Moolenaar     if (qf_list_empty(qfl))
6695a16123a6SBram Moolenaar 	return FAIL;
6696a16123a6SBram Moolenaar 
6697a16123a6SBram Moolenaar     FOR_ALL_QFL_ITEMS(qfl, qfp, i)
6698a16123a6SBram Moolenaar     {
6699858ba06dSBram Moolenaar 	if (eidx > 0)
6700858ba06dSBram Moolenaar 	{
6701858ba06dSBram Moolenaar 	    if (eidx == i)
6702858ba06dSBram Moolenaar 		return get_qfline_items(qfp, list);
6703858ba06dSBram Moolenaar 	}
6704858ba06dSBram Moolenaar 	else if (get_qfline_items(qfp, list) == FAIL)
6705a16123a6SBram Moolenaar 	    return FAIL;
6706a16123a6SBram Moolenaar     }
6707a16123a6SBram Moolenaar 
670805159a0cSBram Moolenaar     return OK;
670905159a0cSBram Moolenaar }
671068b76a69SBram Moolenaar 
671100bf8cd2SBram Moolenaar // Flags used by getqflist()/getloclist() to determine which fields to return.
6712d823fa91SBram Moolenaar enum {
6713d823fa91SBram Moolenaar     QF_GETLIST_NONE	= 0x0,
6714d823fa91SBram Moolenaar     QF_GETLIST_TITLE	= 0x1,
6715d823fa91SBram Moolenaar     QF_GETLIST_ITEMS	= 0x2,
6716d823fa91SBram Moolenaar     QF_GETLIST_NR	= 0x4,
6717d823fa91SBram Moolenaar     QF_GETLIST_WINID	= 0x8,
67188f77c5a4SBram Moolenaar     QF_GETLIST_CONTEXT	= 0x10,
6719a539f4f1SBram Moolenaar     QF_GETLIST_ID	= 0x20,
6720fc2b270cSBram Moolenaar     QF_GETLIST_IDX	= 0x40,
6721fc2b270cSBram Moolenaar     QF_GETLIST_SIZE	= 0x80,
6722b254af31SBram Moolenaar     QF_GETLIST_TICK	= 0x100,
6723c9cc9c78SBram Moolenaar     QF_GETLIST_FILEWINID	= 0x200,
6724647e24baSBram Moolenaar     QF_GETLIST_QFBUFNR	= 0x400,
6725d43906d2SBram Moolenaar     QF_GETLIST_QFTF	= 0x800,
6726d43906d2SBram Moolenaar     QF_GETLIST_ALL	= 0xFFF,
6727d823fa91SBram Moolenaar };
6728d823fa91SBram Moolenaar 
6729d823fa91SBram Moolenaar /*
6730353eeeacSBram Moolenaar  * Parse text from 'di' and return the quickfix list items.
6731353eeeacSBram Moolenaar  * Existing quickfix lists are not modified.
67327adf06f4SBram Moolenaar  */
67337adf06f4SBram Moolenaar     static int
qf_get_list_from_lines(dict_T * what,dictitem_T * di,dict_T * retdict)673436538225SBram Moolenaar qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict)
67357adf06f4SBram Moolenaar {
67367adf06f4SBram Moolenaar     int		status = FAIL;
67377adf06f4SBram Moolenaar     qf_info_T	*qi;
673836538225SBram Moolenaar     char_u	*errorformat = p_efm;
673936538225SBram Moolenaar     dictitem_T	*efm_di;
674036538225SBram Moolenaar     list_T	*l;
67417adf06f4SBram Moolenaar 
674200bf8cd2SBram Moolenaar     // Only a List value is supported
67432c809b7cSBram Moolenaar     if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL)
67447adf06f4SBram Moolenaar     {
674500bf8cd2SBram Moolenaar 	// If errorformat is supplied then use it, otherwise use the 'efm'
674600bf8cd2SBram Moolenaar 	// option setting
674736538225SBram Moolenaar 	if ((efm_di = dict_find(what, (char_u *)"efm", -1)) != NULL)
674836538225SBram Moolenaar 	{
674936538225SBram Moolenaar 	    if (efm_di->di_tv.v_type != VAR_STRING ||
675036538225SBram Moolenaar 		    efm_di->di_tv.vval.v_string == NULL)
675136538225SBram Moolenaar 		return FAIL;
675236538225SBram Moolenaar 	    errorformat = efm_di->di_tv.vval.v_string;
675336538225SBram Moolenaar 	}
6754da73253aSBram Moolenaar 
675536538225SBram Moolenaar 	l = list_alloc();
6756da73253aSBram Moolenaar 	if (l == NULL)
6757da73253aSBram Moolenaar 	    return FAIL;
6758da73253aSBram Moolenaar 
67592d67d307SBram Moolenaar 	qi = qf_alloc_stack(QFLT_INTERNAL);
67607adf06f4SBram Moolenaar 	if (qi != NULL)
67617adf06f4SBram Moolenaar 	{
676236538225SBram Moolenaar 	    if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat,
67637adf06f4SBram Moolenaar 			TRUE, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0)
67647adf06f4SBram Moolenaar 	    {
6765858ba06dSBram Moolenaar 		(void)get_errorlist(qi, NULL, 0, 0, l);
6766fe15b7dfSBram Moolenaar 		qf_free(&qi->qf_lists[0]);
67677adf06f4SBram Moolenaar 	    }
67687adf06f4SBram Moolenaar 	    free(qi);
67697adf06f4SBram Moolenaar 	}
6770da73253aSBram Moolenaar 	dict_add_list(retdict, "items", l);
6771da73253aSBram Moolenaar 	status = OK;
67727adf06f4SBram Moolenaar     }
67737adf06f4SBram Moolenaar 
67747adf06f4SBram Moolenaar     return status;
67757adf06f4SBram Moolenaar }
67767adf06f4SBram Moolenaar 
67777adf06f4SBram Moolenaar /*
67782ec364e9SBram Moolenaar  * Return the quickfix/location list window identifier in the current tabpage.
67792ec364e9SBram Moolenaar  */
67802ec364e9SBram Moolenaar     static int
qf_winid(qf_info_T * qi)67812ec364e9SBram Moolenaar qf_winid(qf_info_T *qi)
67822ec364e9SBram Moolenaar {
67832ec364e9SBram Moolenaar     win_T	*win;
67842ec364e9SBram Moolenaar 
678500bf8cd2SBram Moolenaar     // The quickfix window can be opened even if the quickfix list is not set
678600bf8cd2SBram Moolenaar     // using ":copen". This is not true for location lists.
67872ec364e9SBram Moolenaar     if (qi == NULL)
67882ec364e9SBram Moolenaar 	return 0;
67892ec364e9SBram Moolenaar     win = qf_find_win(qi);
67902ec364e9SBram Moolenaar     if (win != NULL)
67912ec364e9SBram Moolenaar 	return win->w_id;
67922ec364e9SBram Moolenaar     return 0;
67932ec364e9SBram Moolenaar }
67942ec364e9SBram Moolenaar 
67952ec364e9SBram Moolenaar /*
6796647e24baSBram Moolenaar  * Returns the number of the buffer displayed in the quickfix/location list
6797647e24baSBram Moolenaar  * window. If there is no buffer associated with the list, then returns 0.
6798647e24baSBram Moolenaar  */
6799647e24baSBram Moolenaar     static int
qf_getprop_qfbufnr(qf_info_T * qi,dict_T * retdict)6800647e24baSBram Moolenaar qf_getprop_qfbufnr(qf_info_T *qi, dict_T *retdict)
6801647e24baSBram Moolenaar {
6802647e24baSBram Moolenaar     return dict_add_number(retdict, "qfbufnr",
6803647e24baSBram Moolenaar 					(qi == NULL) ? 0 : qi->qf_bufnr);
6804647e24baSBram Moolenaar }
6805647e24baSBram Moolenaar 
6806647e24baSBram Moolenaar /*
6807353eeeacSBram Moolenaar  * Convert the keys in 'what' to quickfix list property flags.
680868b76a69SBram Moolenaar  */
6809353eeeacSBram Moolenaar     static int
qf_getprop_keys2flags(dict_T * what,int loclist)6810c9cc9c78SBram Moolenaar qf_getprop_keys2flags(dict_T *what, int loclist)
6811d823fa91SBram Moolenaar {
6812d823fa91SBram Moolenaar     int		flags = QF_GETLIST_NONE;
6813d823fa91SBram Moolenaar 
6814a6d4849cSBram Moolenaar     if (dict_find(what, (char_u *)"all", -1) != NULL)
6815c9cc9c78SBram Moolenaar     {
6816a6d4849cSBram Moolenaar 	flags |= QF_GETLIST_ALL;
6817c9cc9c78SBram Moolenaar 	if (!loclist)
6818c9cc9c78SBram Moolenaar 	    // File window ID is applicable only to location list windows
6819c9cc9c78SBram Moolenaar 	    flags &= ~ QF_GETLIST_FILEWINID;
6820c9cc9c78SBram Moolenaar     }
6821d823fa91SBram Moolenaar 
6822a6d4849cSBram Moolenaar     if (dict_find(what, (char_u *)"title", -1) != NULL)
6823a6d4849cSBram Moolenaar 	flags |= QF_GETLIST_TITLE;
6824a6d4849cSBram Moolenaar 
6825a6d4849cSBram Moolenaar     if (dict_find(what, (char_u *)"nr", -1) != NULL)
6826a6d4849cSBram Moolenaar 	flags |= QF_GETLIST_NR;
6827a6d4849cSBram Moolenaar 
6828a6d4849cSBram Moolenaar     if (dict_find(what, (char_u *)"winid", -1) != NULL)
6829a6d4849cSBram Moolenaar 	flags |= QF_GETLIST_WINID;
6830a6d4849cSBram Moolenaar 
6831a6d4849cSBram Moolenaar     if (dict_find(what, (char_u *)"context", -1) != NULL)
6832a6d4849cSBram Moolenaar 	flags |= QF_GETLIST_CONTEXT;
6833a6d4849cSBram Moolenaar 
6834a6d4849cSBram Moolenaar     if (dict_find(what, (char_u *)"id", -1) != NULL)
6835a6d4849cSBram Moolenaar 	flags |= QF_GETLIST_ID;
6836a6d4849cSBram Moolenaar 
6837a6d4849cSBram Moolenaar     if (dict_find(what, (char_u *)"items", -1) != NULL)
6838a6d4849cSBram Moolenaar 	flags |= QF_GETLIST_ITEMS;
6839a6d4849cSBram Moolenaar 
6840a6d4849cSBram Moolenaar     if (dict_find(what, (char_u *)"idx", -1) != NULL)
6841a6d4849cSBram Moolenaar 	flags |= QF_GETLIST_IDX;
6842a6d4849cSBram Moolenaar 
6843a6d4849cSBram Moolenaar     if (dict_find(what, (char_u *)"size", -1) != NULL)
6844a6d4849cSBram Moolenaar 	flags |= QF_GETLIST_SIZE;
6845a6d4849cSBram Moolenaar 
6846b254af31SBram Moolenaar     if (dict_find(what, (char_u *)"changedtick", -1) != NULL)
6847b254af31SBram Moolenaar 	flags |= QF_GETLIST_TICK;
6848b254af31SBram Moolenaar 
6849c9cc9c78SBram Moolenaar     if (loclist && dict_find(what, (char_u *)"filewinid", -1) != NULL)
6850c9cc9c78SBram Moolenaar 	flags |= QF_GETLIST_FILEWINID;
6851c9cc9c78SBram Moolenaar 
6852647e24baSBram Moolenaar     if (dict_find(what, (char_u *)"qfbufnr", -1) != NULL)
6853647e24baSBram Moolenaar 	flags |= QF_GETLIST_QFBUFNR;
6854647e24baSBram Moolenaar 
6855d43906d2SBram Moolenaar     if (dict_find(what, (char_u *)"quickfixtextfunc", -1) != NULL)
6856d43906d2SBram Moolenaar 	flags |= QF_GETLIST_QFTF;
6857d43906d2SBram Moolenaar 
6858353eeeacSBram Moolenaar     return flags;
6859353eeeacSBram Moolenaar }
6860353eeeacSBram Moolenaar 
6861353eeeacSBram Moolenaar /*
6862353eeeacSBram Moolenaar  * Return the quickfix list index based on 'nr' or 'id' in 'what'.
6863353eeeacSBram Moolenaar  * If 'nr' and 'id' are not present in 'what' then return the current
6864353eeeacSBram Moolenaar  * quickfix list index.
6865353eeeacSBram Moolenaar  * If 'nr' is zero then return the current quickfix list index.
6866353eeeacSBram Moolenaar  * If 'nr' is '$' then return the last quickfix list index.
6867353eeeacSBram Moolenaar  * If 'id' is present then return the index of the quickfix list with that id.
6868353eeeacSBram Moolenaar  * If 'id' is zero then return the quickfix list index specified by 'nr'.
6869353eeeacSBram Moolenaar  * Return -1, if quickfix list is not present or if the stack is empty.
6870353eeeacSBram Moolenaar  */
6871353eeeacSBram Moolenaar     static int
qf_getprop_qfidx(qf_info_T * qi,dict_T * what)6872353eeeacSBram Moolenaar qf_getprop_qfidx(qf_info_T *qi, dict_T *what)
6873a6d4849cSBram Moolenaar {
6874353eeeacSBram Moolenaar     int		qf_idx;
6875353eeeacSBram Moolenaar     dictitem_T	*di;
6876353eeeacSBram Moolenaar 
687700bf8cd2SBram Moolenaar     qf_idx = qi->qf_curlist;	// default is the current list
6878d823fa91SBram Moolenaar     if ((di = dict_find(what, (char_u *)"nr", -1)) != NULL)
6879d823fa91SBram Moolenaar     {
688000bf8cd2SBram Moolenaar 	// Use the specified quickfix/location list
6881d823fa91SBram Moolenaar 	if (di->di_tv.v_type == VAR_NUMBER)
6882d823fa91SBram Moolenaar 	{
688300bf8cd2SBram Moolenaar 	    // for zero use the current list
6884890680caSBram Moolenaar 	    if (di->di_tv.vval.v_number != 0)
6885890680caSBram Moolenaar 	    {
6886d823fa91SBram Moolenaar 		qf_idx = di->di_tv.vval.v_number - 1;
6887d823fa91SBram Moolenaar 		if (qf_idx < 0 || qf_idx >= qi->qf_listcount)
6888a2aa8a2bSBram Moolenaar 		    qf_idx = INVALID_QFIDX;
688955b69264SBram Moolenaar 	    }
689055b69264SBram Moolenaar 	}
6891a0ca7d00SBram Moolenaar 	else if (di->di_tv.v_type == VAR_STRING
6892a0ca7d00SBram Moolenaar 		&& di->di_tv.vval.v_string != NULL
6893a0ca7d00SBram Moolenaar 		&& STRCMP(di->di_tv.vval.v_string, "$") == 0)
689400bf8cd2SBram Moolenaar 	    // Get the last quickfix list number
6895875feea6SBram Moolenaar 	    qf_idx = qi->qf_listcount - 1;
6896875feea6SBram Moolenaar 	else
6897a2aa8a2bSBram Moolenaar 	    qf_idx = INVALID_QFIDX;
6898d823fa91SBram Moolenaar     }
6899a539f4f1SBram Moolenaar 
6900a539f4f1SBram Moolenaar     if ((di = dict_find(what, (char_u *)"id", -1)) != NULL)
6901a539f4f1SBram Moolenaar     {
690200bf8cd2SBram Moolenaar 	// Look for a list with the specified id
6903a539f4f1SBram Moolenaar 	if (di->di_tv.v_type == VAR_NUMBER)
6904a539f4f1SBram Moolenaar 	{
690500bf8cd2SBram Moolenaar 	    // For zero, use the current list or the list specified by 'nr'
6906a539f4f1SBram Moolenaar 	    if (di->di_tv.vval.v_number != 0)
6907b4d5fbabSBram Moolenaar 		qf_idx = qf_id2nr(qi, di->di_tv.vval.v_number);
6908a539f4f1SBram Moolenaar 	}
6909d823fa91SBram Moolenaar 	else
6910a2aa8a2bSBram Moolenaar 	    qf_idx = INVALID_QFIDX;
6911a6d4849cSBram Moolenaar     }
6912353eeeacSBram Moolenaar 
6913353eeeacSBram Moolenaar     return qf_idx;
6914d823fa91SBram Moolenaar }
6915d823fa91SBram Moolenaar 
6916353eeeacSBram Moolenaar /*
6917353eeeacSBram Moolenaar  * Return default values for quickfix list properties in retdict.
6918353eeeacSBram Moolenaar  */
6919353eeeacSBram Moolenaar     static int
qf_getprop_defaults(qf_info_T * qi,int flags,int locstack,dict_T * retdict)69202d67d307SBram Moolenaar qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *retdict)
6921a6d4849cSBram Moolenaar {
6922353eeeacSBram Moolenaar     int		status = OK;
6923353eeeacSBram Moolenaar 
6924a6d4849cSBram Moolenaar     if (flags & QF_GETLIST_TITLE)
6925e0be167aSBram Moolenaar 	status = dict_add_string(retdict, "title", (char_u *)"");
6926a6d4849cSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_ITEMS))
6927a6d4849cSBram Moolenaar     {
6928a6d4849cSBram Moolenaar 	list_T	*l = list_alloc();
6929a6d4849cSBram Moolenaar 	if (l != NULL)
6930a6d4849cSBram Moolenaar 	    status = dict_add_list(retdict, "items", l);
6931a6d4849cSBram Moolenaar 	else
6932a6d4849cSBram Moolenaar 	    status = FAIL;
6933a6d4849cSBram Moolenaar     }
6934a6d4849cSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_NR))
6935e0be167aSBram Moolenaar 	status = dict_add_number(retdict, "nr", 0);
6936a6d4849cSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_WINID))
6937e0be167aSBram Moolenaar 	status = dict_add_number(retdict, "winid", qf_winid(qi));
6938a6d4849cSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_CONTEXT))
6939e0be167aSBram Moolenaar 	status = dict_add_string(retdict, "context", (char_u *)"");
6940a6d4849cSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_ID))
6941e0be167aSBram Moolenaar 	status = dict_add_number(retdict, "id", 0);
6942a6d4849cSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_IDX))
6943e0be167aSBram Moolenaar 	status = dict_add_number(retdict, "idx", 0);
6944a6d4849cSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_SIZE))
6945e0be167aSBram Moolenaar 	status = dict_add_number(retdict, "size", 0);
6946b254af31SBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_TICK))
6947e0be167aSBram Moolenaar 	status = dict_add_number(retdict, "changedtick", 0);
69482d67d307SBram Moolenaar     if ((status == OK) && locstack && (flags & QF_GETLIST_FILEWINID))
6949c9cc9c78SBram Moolenaar 	status = dict_add_number(retdict, "filewinid", 0);
6950647e24baSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_QFBUFNR))
6951647e24baSBram Moolenaar 	status = qf_getprop_qfbufnr(qi, retdict);
6952d43906d2SBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_QFTF))
6953d43906d2SBram Moolenaar 	status = dict_add_string(retdict, "quickfixtextfunc", (char_u *)"");
6954d823fa91SBram Moolenaar 
6955a6d4849cSBram Moolenaar     return status;
6956a6d4849cSBram Moolenaar }
6957fc2b270cSBram Moolenaar 
6958353eeeacSBram Moolenaar /*
6959353eeeacSBram Moolenaar  * Return the quickfix list title as 'title' in retdict
6960353eeeacSBram Moolenaar  */
6961353eeeacSBram Moolenaar     static int
qf_getprop_title(qf_list_T * qfl,dict_T * retdict)6962108e7b42SBram Moolenaar qf_getprop_title(qf_list_T *qfl, dict_T *retdict)
6963d823fa91SBram Moolenaar {
6964108e7b42SBram Moolenaar     return dict_add_string(retdict, "title", qfl->qf_title);
6965d823fa91SBram Moolenaar }
6966353eeeacSBram Moolenaar 
6967353eeeacSBram Moolenaar /*
6968c9cc9c78SBram Moolenaar  * Returns the identifier of the window used to display files from a location
6969c9cc9c78SBram Moolenaar  * list.  If there is no associated window, then returns 0. Useful only when
6970c9cc9c78SBram Moolenaar  * called from a location list window.
6971c9cc9c78SBram Moolenaar  */
6972c9cc9c78SBram Moolenaar     static int
qf_getprop_filewinid(win_T * wp,qf_info_T * qi,dict_T * retdict)6973c9cc9c78SBram Moolenaar qf_getprop_filewinid(win_T *wp, qf_info_T *qi, dict_T *retdict)
6974c9cc9c78SBram Moolenaar {
6975c9cc9c78SBram Moolenaar     int winid = 0;
6976c9cc9c78SBram Moolenaar 
6977c9cc9c78SBram Moolenaar     if (wp != NULL && IS_LL_WINDOW(wp))
6978c9cc9c78SBram Moolenaar     {
6979c9cc9c78SBram Moolenaar 	win_T	*ll_wp = qf_find_win_with_loclist(qi);
6980c9cc9c78SBram Moolenaar 	if (ll_wp != NULL)
6981c9cc9c78SBram Moolenaar 	    winid = ll_wp->w_id;
6982c9cc9c78SBram Moolenaar     }
6983c9cc9c78SBram Moolenaar 
6984c9cc9c78SBram Moolenaar     return dict_add_number(retdict, "filewinid", winid);
6985c9cc9c78SBram Moolenaar }
6986c9cc9c78SBram Moolenaar 
6987c9cc9c78SBram Moolenaar /*
6988858ba06dSBram Moolenaar  * Return the quickfix list items/entries as 'items' in retdict.
6989858ba06dSBram Moolenaar  * If eidx is not 0, then return the item at the specified index.
6990353eeeacSBram Moolenaar  */
6991353eeeacSBram Moolenaar     static int
qf_getprop_items(qf_info_T * qi,int qf_idx,int eidx,dict_T * retdict)6992858ba06dSBram Moolenaar qf_getprop_items(qf_info_T *qi, int qf_idx, int eidx, dict_T *retdict)
69936a8958dbSBram Moolenaar {
6994353eeeacSBram Moolenaar     int		status = OK;
69956a8958dbSBram Moolenaar     list_T	*l = list_alloc();
69966a8958dbSBram Moolenaar     if (l != NULL)
69976a8958dbSBram Moolenaar     {
6998858ba06dSBram Moolenaar 	(void)get_errorlist(qi, NULL, qf_idx, eidx, l);
69996a8958dbSBram Moolenaar 	dict_add_list(retdict, "items", l);
70006a8958dbSBram Moolenaar     }
700186f100dcSBram Moolenaar     else
700286f100dcSBram Moolenaar 	status = FAIL;
7003353eeeacSBram Moolenaar 
7004353eeeacSBram Moolenaar     return status;
70056a8958dbSBram Moolenaar }
7006d823fa91SBram Moolenaar 
7007353eeeacSBram Moolenaar /*
7008353eeeacSBram Moolenaar  * Return the quickfix list context (if any) as 'context' in retdict.
7009353eeeacSBram Moolenaar  */
7010353eeeacSBram Moolenaar     static int
qf_getprop_ctx(qf_list_T * qfl,dict_T * retdict)7011108e7b42SBram Moolenaar qf_getprop_ctx(qf_list_T *qfl, dict_T *retdict)
70128f77c5a4SBram Moolenaar {
7013353eeeacSBram Moolenaar     int		status;
7014353eeeacSBram Moolenaar     dictitem_T	*di;
7015353eeeacSBram Moolenaar 
7016108e7b42SBram Moolenaar     if (qfl->qf_ctx != NULL)
70178f77c5a4SBram Moolenaar     {
70188f77c5a4SBram Moolenaar 	di = dictitem_alloc((char_u *)"context");
70198f77c5a4SBram Moolenaar 	if (di != NULL)
70208f77c5a4SBram Moolenaar 	{
7021108e7b42SBram Moolenaar 	    copy_tv(qfl->qf_ctx, &di->di_tv);
702286f100dcSBram Moolenaar 	    status = dict_add(retdict, di);
702386f100dcSBram Moolenaar 	    if (status == FAIL)
7024beb9cb19SBram Moolenaar 		dictitem_free(di);
70258f77c5a4SBram Moolenaar 	}
702686f100dcSBram Moolenaar 	else
702786f100dcSBram Moolenaar 	    status = FAIL;
70288f77c5a4SBram Moolenaar     }
70298f77c5a4SBram Moolenaar     else
7030e0be167aSBram Moolenaar 	status = dict_add_string(retdict, "context", (char_u *)"");
7031353eeeacSBram Moolenaar 
7032353eeeacSBram Moolenaar     return status;
70338f77c5a4SBram Moolenaar }
70348f77c5a4SBram Moolenaar 
7035353eeeacSBram Moolenaar /*
7036858ba06dSBram Moolenaar  * Return the current quickfix list index as 'idx' in retdict.
7037858ba06dSBram Moolenaar  * If a specific entry index (eidx) is supplied, then use that.
7038353eeeacSBram Moolenaar  */
7039353eeeacSBram Moolenaar     static int
qf_getprop_idx(qf_list_T * qfl,int eidx,dict_T * retdict)7040858ba06dSBram Moolenaar qf_getprop_idx(qf_list_T *qfl, int eidx, dict_T *retdict)
7041fc2b270cSBram Moolenaar {
7042858ba06dSBram Moolenaar     if (eidx == 0)
7043858ba06dSBram Moolenaar     {
7044858ba06dSBram Moolenaar 	eidx = qfl->qf_index;
70450398e00aSBram Moolenaar 	if (qf_list_empty(qfl))
7046108e7b42SBram Moolenaar 	    // For empty lists, current index is set to 0
7047858ba06dSBram Moolenaar 	    eidx = 0;
7048858ba06dSBram Moolenaar     }
7049858ba06dSBram Moolenaar     return dict_add_number(retdict, "idx", eidx);
7050fc2b270cSBram Moolenaar }
7051fc2b270cSBram Moolenaar 
7052353eeeacSBram Moolenaar /*
7053d43906d2SBram Moolenaar  * Return the 'quickfixtextfunc' function of a quickfix/location list
7054d43906d2SBram Moolenaar  */
7055d43906d2SBram Moolenaar     static int
qf_getprop_qftf(qf_list_T * qfl,dict_T * retdict)7056d43906d2SBram Moolenaar qf_getprop_qftf(qf_list_T *qfl, dict_T *retdict)
7057d43906d2SBram Moolenaar {
7058d43906d2SBram Moolenaar     int		status;
7059d43906d2SBram Moolenaar 
7060d43906d2SBram Moolenaar     if (qfl->qftf_cb.cb_name != NULL)
7061d43906d2SBram Moolenaar     {
7062d43906d2SBram Moolenaar 	typval_T	tv;
7063d43906d2SBram Moolenaar 
7064d43906d2SBram Moolenaar 	put_callback(&qfl->qftf_cb, &tv);
7065d43906d2SBram Moolenaar 	status = dict_add_tv(retdict, "quickfixtextfunc", &tv);
7066d43906d2SBram Moolenaar 	clear_tv(&tv);
7067d43906d2SBram Moolenaar     }
7068d43906d2SBram Moolenaar     else
7069d43906d2SBram Moolenaar 	status = dict_add_string(retdict, "quickfixtextfunc", (char_u *)"");
7070d43906d2SBram Moolenaar 
7071d43906d2SBram Moolenaar     return status;
7072d43906d2SBram Moolenaar }
7073d43906d2SBram Moolenaar 
7074d43906d2SBram Moolenaar /*
7075353eeeacSBram Moolenaar  * Return quickfix/location list details (title) as a
7076353eeeacSBram Moolenaar  * dictionary. 'what' contains the details to return. If 'list_idx' is -1,
7077353eeeacSBram Moolenaar  * then current list is used. Otherwise the specified list is used.
7078353eeeacSBram Moolenaar  */
7079e677df8dSBram Moolenaar     static int
qf_get_properties(win_T * wp,dict_T * what,dict_T * retdict)7080353eeeacSBram Moolenaar qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
7081353eeeacSBram Moolenaar {
7082353eeeacSBram Moolenaar     qf_info_T	*qi = &ql_info;
7083fe15b7dfSBram Moolenaar     qf_list_T	*qfl;
7084353eeeacSBram Moolenaar     int		status = OK;
7085108e7b42SBram Moolenaar     int		qf_idx = INVALID_QFIDX;
7086858ba06dSBram Moolenaar     int		eidx = 0;
7087353eeeacSBram Moolenaar     dictitem_T	*di;
7088353eeeacSBram Moolenaar     int		flags = QF_GETLIST_NONE;
7089353eeeacSBram Moolenaar 
7090353eeeacSBram Moolenaar     if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL)
7091353eeeacSBram Moolenaar 	return qf_get_list_from_lines(what, di, retdict);
7092353eeeacSBram Moolenaar 
7093353eeeacSBram Moolenaar     if (wp != NULL)
7094353eeeacSBram Moolenaar 	qi = GET_LOC_LIST(wp);
7095353eeeacSBram Moolenaar 
7096c9cc9c78SBram Moolenaar     flags = qf_getprop_keys2flags(what, (wp != NULL));
7097353eeeacSBram Moolenaar 
7098019dfe68SBram Moolenaar     if (!qf_stack_empty(qi))
7099353eeeacSBram Moolenaar 	qf_idx = qf_getprop_qfidx(qi, what);
7100353eeeacSBram Moolenaar 
710100bf8cd2SBram Moolenaar     // List is not present or is empty
7102019dfe68SBram Moolenaar     if (qf_stack_empty(qi) || qf_idx == INVALID_QFIDX)
71032d67d307SBram Moolenaar 	return qf_getprop_defaults(qi, flags, wp != NULL, retdict);
7104353eeeacSBram Moolenaar 
71050398e00aSBram Moolenaar     qfl = qf_get_list(qi, qf_idx);
7106fe15b7dfSBram Moolenaar 
7107858ba06dSBram Moolenaar     // If an entry index is specified, use that
7108858ba06dSBram Moolenaar     if ((di = dict_find(what, (char_u *)"idx", -1)) != NULL)
7109858ba06dSBram Moolenaar     {
7110858ba06dSBram Moolenaar 	if (di->di_tv.v_type != VAR_NUMBER)
7111858ba06dSBram Moolenaar 	    return FAIL;
7112858ba06dSBram Moolenaar 	eidx = di->di_tv.vval.v_number;
7113858ba06dSBram Moolenaar     }
7114858ba06dSBram Moolenaar 
7115353eeeacSBram Moolenaar     if (flags & QF_GETLIST_TITLE)
7116108e7b42SBram Moolenaar 	status = qf_getprop_title(qfl, retdict);
7117353eeeacSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_NR))
7118e0be167aSBram Moolenaar 	status = dict_add_number(retdict, "nr", qf_idx + 1);
7119353eeeacSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_WINID))
7120e0be167aSBram Moolenaar 	status = dict_add_number(retdict, "winid", qf_winid(qi));
7121353eeeacSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_ITEMS))
7122858ba06dSBram Moolenaar 	status = qf_getprop_items(qi, qf_idx, eidx, retdict);
7123353eeeacSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_CONTEXT))
7124108e7b42SBram Moolenaar 	status = qf_getprop_ctx(qfl, retdict);
7125353eeeacSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_ID))
7126fe15b7dfSBram Moolenaar 	status = dict_add_number(retdict, "id", qfl->qf_id);
7127353eeeacSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_IDX))
7128858ba06dSBram Moolenaar 	status = qf_getprop_idx(qfl, eidx, retdict);
7129fc2b270cSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_SIZE))
7130fe15b7dfSBram Moolenaar 	status = dict_add_number(retdict, "size", qfl->qf_count);
7131b254af31SBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_TICK))
7132fe15b7dfSBram Moolenaar 	status = dict_add_number(retdict, "changedtick", qfl->qf_changedtick);
7133c9cc9c78SBram Moolenaar     if ((status == OK) && (wp != NULL) && (flags & QF_GETLIST_FILEWINID))
7134c9cc9c78SBram Moolenaar 	status = qf_getprop_filewinid(wp, qi, retdict);
7135647e24baSBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_QFBUFNR))
7136647e24baSBram Moolenaar 	status = qf_getprop_qfbufnr(qi, retdict);
7137d43906d2SBram Moolenaar     if ((status == OK) && (flags & QF_GETLIST_QFTF))
7138d43906d2SBram Moolenaar 	status = qf_getprop_qftf(qfl, retdict);
7139b254af31SBram Moolenaar 
7140d823fa91SBram Moolenaar     return status;
7141d823fa91SBram Moolenaar }
7142d823fa91SBram Moolenaar 
7143d823fa91SBram Moolenaar /*
71446f6ef7c1SBram Moolenaar  * Add a new quickfix entry to list at 'qf_idx' in the stack 'qi' from the
71459752c72fSBram Moolenaar  * items in the dict 'd'. If it is a valid error entry, then set 'valid_entry'
71469752c72fSBram Moolenaar  * to TRUE.
71476f6ef7c1SBram Moolenaar  */
71486f6ef7c1SBram Moolenaar     static int
qf_add_entry_from_dict(qf_list_T * qfl,dict_T * d,int first_entry,int * valid_entry)71496f6ef7c1SBram Moolenaar qf_add_entry_from_dict(
71500398e00aSBram Moolenaar 	qf_list_T	*qfl,
71516f6ef7c1SBram Moolenaar 	dict_T		*d,
71529752c72fSBram Moolenaar 	int		first_entry,
71539752c72fSBram Moolenaar 	int		*valid_entry)
71546f6ef7c1SBram Moolenaar {
71556f6ef7c1SBram Moolenaar     static int	did_bufnr_emsg;
71566f6ef7c1SBram Moolenaar     char_u	*filename, *module, *pattern, *text, *type;
71576864efa5Sthinca     int		bufnum, valid, status, col, end_col, vcol, nr;
71586864efa5Sthinca     long	lnum, end_lnum;
71596f6ef7c1SBram Moolenaar 
71606f6ef7c1SBram Moolenaar     if (first_entry)
71616f6ef7c1SBram Moolenaar 	did_bufnr_emsg = FALSE;
71626f6ef7c1SBram Moolenaar 
71638f66717aSBram Moolenaar     filename = dict_get_string(d, (char_u *)"filename", TRUE);
71648f66717aSBram Moolenaar     module = dict_get_string(d, (char_u *)"module", TRUE);
71658f66717aSBram Moolenaar     bufnum = (int)dict_get_number(d, (char_u *)"bufnr");
71668f66717aSBram Moolenaar     lnum = (int)dict_get_number(d, (char_u *)"lnum");
71676864efa5Sthinca     end_lnum = (int)dict_get_number(d, (char_u *)"end_lnum");
71688f66717aSBram Moolenaar     col = (int)dict_get_number(d, (char_u *)"col");
71696864efa5Sthinca     end_col = (int)dict_get_number(d, (char_u *)"end_col");
71708f66717aSBram Moolenaar     vcol = (int)dict_get_number(d, (char_u *)"vcol");
71718f66717aSBram Moolenaar     nr = (int)dict_get_number(d, (char_u *)"nr");
71728f66717aSBram Moolenaar     type = dict_get_string(d, (char_u *)"type", TRUE);
71738f66717aSBram Moolenaar     pattern = dict_get_string(d, (char_u *)"pattern", TRUE);
71748f66717aSBram Moolenaar     text = dict_get_string(d, (char_u *)"text", TRUE);
71756f6ef7c1SBram Moolenaar     if (text == NULL)
71766f6ef7c1SBram Moolenaar 	text = vim_strsave((char_u *)"");
71776f6ef7c1SBram Moolenaar 
71786f6ef7c1SBram Moolenaar     valid = TRUE;
71796f6ef7c1SBram Moolenaar     if ((filename == NULL && bufnum == 0) || (lnum == 0 && pattern == NULL))
71806f6ef7c1SBram Moolenaar 	valid = FALSE;
71816f6ef7c1SBram Moolenaar 
71826f6ef7c1SBram Moolenaar     // Mark entries with non-existing buffer number as not valid. Give the
71836f6ef7c1SBram Moolenaar     // error message only once.
71846f6ef7c1SBram Moolenaar     if (bufnum != 0 && (buflist_findnr(bufnum) == NULL))
71856f6ef7c1SBram Moolenaar     {
71866f6ef7c1SBram Moolenaar 	if (!did_bufnr_emsg)
71876f6ef7c1SBram Moolenaar 	{
71886f6ef7c1SBram Moolenaar 	    did_bufnr_emsg = TRUE;
7189b5443cc4SBram Moolenaar 	    semsg(_("E92: Buffer %d not found"), bufnum);
71906f6ef7c1SBram Moolenaar 	}
71916f6ef7c1SBram Moolenaar 	valid = FALSE;
71926f6ef7c1SBram Moolenaar 	bufnum = 0;
71936f6ef7c1SBram Moolenaar     }
71946f6ef7c1SBram Moolenaar 
71956f6ef7c1SBram Moolenaar     // If the 'valid' field is present it overrules the detected value.
71966f6ef7c1SBram Moolenaar     if ((dict_find(d, (char_u *)"valid", -1)) != NULL)
7197401f0c07SBram Moolenaar 	valid = (int)dict_get_bool(d, (char_u *)"valid", FALSE);
71986f6ef7c1SBram Moolenaar 
71990398e00aSBram Moolenaar     status =  qf_add_entry(qfl,
72006f6ef7c1SBram Moolenaar 			NULL,		// dir
72016f6ef7c1SBram Moolenaar 			filename,
72026f6ef7c1SBram Moolenaar 			module,
72036f6ef7c1SBram Moolenaar 			bufnum,
72046f6ef7c1SBram Moolenaar 			text,
72056f6ef7c1SBram Moolenaar 			lnum,
72066864efa5Sthinca 			end_lnum,
72076f6ef7c1SBram Moolenaar 			col,
72086864efa5Sthinca 			end_col,
72096f6ef7c1SBram Moolenaar 			vcol,		// vis_col
72106f6ef7c1SBram Moolenaar 			pattern,	// search pattern
72116f6ef7c1SBram Moolenaar 			nr,
72126f6ef7c1SBram Moolenaar 			type == NULL ? NUL : *type,
72136f6ef7c1SBram Moolenaar 			valid);
72146f6ef7c1SBram Moolenaar 
72156f6ef7c1SBram Moolenaar     vim_free(filename);
72166f6ef7c1SBram Moolenaar     vim_free(module);
72176f6ef7c1SBram Moolenaar     vim_free(pattern);
72186f6ef7c1SBram Moolenaar     vim_free(text);
72196f6ef7c1SBram Moolenaar     vim_free(type);
72206f6ef7c1SBram Moolenaar 
72219752c72fSBram Moolenaar     if (valid)
72229752c72fSBram Moolenaar 	*valid_entry = TRUE;
72239752c72fSBram Moolenaar 
72246f6ef7c1SBram Moolenaar     return status;
72256f6ef7c1SBram Moolenaar }
72266f6ef7c1SBram Moolenaar 
72276f6ef7c1SBram Moolenaar /*
7228d823fa91SBram Moolenaar  * Add list of entries to quickfix/location list. Each list entry is
7229d823fa91SBram Moolenaar  * a dictionary with item information.
7230d823fa91SBram Moolenaar  */
7231d823fa91SBram Moolenaar     static int
qf_add_entries(qf_info_T * qi,int qf_idx,list_T * list,char_u * title,int action)7232d823fa91SBram Moolenaar qf_add_entries(
7233d823fa91SBram Moolenaar 	qf_info_T	*qi,
7234a3921f48SBram Moolenaar 	int		qf_idx,
723505540976SBram Moolenaar 	list_T		*list,
7236d823fa91SBram Moolenaar 	char_u		*title,
7237d823fa91SBram Moolenaar 	int		action)
723868b76a69SBram Moolenaar {
72390398e00aSBram Moolenaar     qf_list_T	*qfl = qf_get_list(qi, qf_idx);
724068b76a69SBram Moolenaar     listitem_T	*li;
724168b76a69SBram Moolenaar     dict_T	*d;
7242864293abSBram Moolenaar     qfline_T	*old_last = NULL;
724368b76a69SBram Moolenaar     int		retval = OK;
72449752c72fSBram Moolenaar     int		valid_entry = FALSE;
724568b76a69SBram Moolenaar 
7246a3921f48SBram Moolenaar     if (action == ' ' || qf_idx == qi->qf_listcount)
7247a3921f48SBram Moolenaar     {
724800bf8cd2SBram Moolenaar 	// make place for a new list
724994116159SBram Moolenaar 	qf_new_list(qi, title);
7250a3921f48SBram Moolenaar 	qf_idx = qi->qf_curlist;
72510398e00aSBram Moolenaar 	qfl = qf_get_list(qi, qf_idx);
7252a3921f48SBram Moolenaar     }
72530398e00aSBram Moolenaar     else if (action == 'a' && !qf_list_empty(qfl))
725400bf8cd2SBram Moolenaar 	// Adding to existing list, use last entry.
7255fe15b7dfSBram Moolenaar 	old_last = qfl->qf_last;
725635c54e56SBram Moolenaar     else if (action == 'r')
7257fb60409aSBram Moolenaar     {
7258fe15b7dfSBram Moolenaar 	qf_free_items(qfl);
7259fe15b7dfSBram Moolenaar 	qf_store_title(qfl, title);
7260fb60409aSBram Moolenaar     }
726168b76a69SBram Moolenaar 
7262aeea7215SBram Moolenaar     FOR_ALL_LIST_ITEMS(list, li)
726368b76a69SBram Moolenaar     {
726468b76a69SBram Moolenaar 	if (li->li_tv.v_type != VAR_DICT)
726500bf8cd2SBram Moolenaar 	    continue; // Skip non-dict items
726668b76a69SBram Moolenaar 
726768b76a69SBram Moolenaar 	d = li->li_tv.vval.v_dict;
726868b76a69SBram Moolenaar 	if (d == NULL)
726968b76a69SBram Moolenaar 	    continue;
727068b76a69SBram Moolenaar 
72710398e00aSBram Moolenaar 	retval = qf_add_entry_from_dict(qfl, d, li == list->lv_first,
72729752c72fSBram Moolenaar 								&valid_entry);
727395946f12SBram Moolenaar 	if (retval == QF_FAIL)
727468b76a69SBram Moolenaar 	    break;
727568b76a69SBram Moolenaar     }
727668b76a69SBram Moolenaar 
72779752c72fSBram Moolenaar     // Check if any valid error entries are added to the list.
72789752c72fSBram Moolenaar     if (valid_entry)
72799752c72fSBram Moolenaar 	qfl->qf_nonevalid = FALSE;
72809752c72fSBram Moolenaar     else if (qfl->qf_index == 0)
728100bf8cd2SBram Moolenaar 	// no valid entry
7282fe15b7dfSBram Moolenaar 	qfl->qf_nonevalid = TRUE;
72839752c72fSBram Moolenaar 
72849752c72fSBram Moolenaar     // If not appending to the list, set the current error to the first entry
7285b6fa30ccSBram Moolenaar     if (action != 'a')
7286fe15b7dfSBram Moolenaar 	qfl->qf_ptr = qfl->qf_start;
72879752c72fSBram Moolenaar 
72889752c72fSBram Moolenaar     // Update the current error index if not appending to the list or if the
72899752c72fSBram Moolenaar     // list was empty before and it is not empty now.
72900398e00aSBram Moolenaar     if ((action != 'a' || qfl->qf_index == 0) && !qf_list_empty(qfl))
7291fe15b7dfSBram Moolenaar 	qfl->qf_index = 1;
729268b76a69SBram Moolenaar 
729300bf8cd2SBram Moolenaar     // Don't update the cursor in quickfix window when appending entries
7294864293abSBram Moolenaar     qf_update_buffer(qi, old_last);
729568b76a69SBram Moolenaar 
729668b76a69SBram Moolenaar     return retval;
729768b76a69SBram Moolenaar }
7298d823fa91SBram Moolenaar 
7299a2aa8a2bSBram Moolenaar /*
7300a2aa8a2bSBram Moolenaar  * Get the quickfix list index from 'nr' or 'id'
7301a2aa8a2bSBram Moolenaar  */
7302d823fa91SBram Moolenaar     static int
qf_setprop_get_qfidx(qf_info_T * qi,dict_T * what,int action,int * newlist)7303a2aa8a2bSBram Moolenaar qf_setprop_get_qfidx(
7304a2aa8a2bSBram Moolenaar 	qf_info_T	*qi,
7305a2aa8a2bSBram Moolenaar 	dict_T		*what,
7306a2aa8a2bSBram Moolenaar 	int		action,
7307a2aa8a2bSBram Moolenaar 	int		*newlist)
7308d823fa91SBram Moolenaar {
7309d823fa91SBram Moolenaar     dictitem_T	*di;
731000bf8cd2SBram Moolenaar     int		qf_idx = qi->qf_curlist;    // default is the current list
73112b529bb6SBram Moolenaar 
7312d823fa91SBram Moolenaar     if ((di = dict_find(what, (char_u *)"nr", -1)) != NULL)
7313d823fa91SBram Moolenaar     {
731400bf8cd2SBram Moolenaar 	// Use the specified quickfix/location list
7315d823fa91SBram Moolenaar 	if (di->di_tv.v_type == VAR_NUMBER)
7316d823fa91SBram Moolenaar 	{
731700bf8cd2SBram Moolenaar 	    // for zero use the current list
73186e62da3eSBram Moolenaar 	    if (di->di_tv.vval.v_number != 0)
7319d823fa91SBram Moolenaar 		qf_idx = di->di_tv.vval.v_number - 1;
73206a8958dbSBram Moolenaar 
732155b69264SBram Moolenaar 	    if ((action == ' ' || action == 'a') && qf_idx == qi->qf_listcount)
732255b69264SBram Moolenaar 	    {
732300bf8cd2SBram Moolenaar 		// When creating a new list, accept qf_idx pointing to the next
732400bf8cd2SBram Moolenaar 		// non-available list and add the new list at the end of the
732500bf8cd2SBram Moolenaar 		// stack.
7326a2aa8a2bSBram Moolenaar 		*newlist = TRUE;
7327019dfe68SBram Moolenaar 		qf_idx = qf_stack_empty(qi) ? 0 : qi->qf_listcount - 1;
732855b69264SBram Moolenaar 	    }
73296a8958dbSBram Moolenaar 	    else if (qf_idx < 0 || qf_idx >= qi->qf_listcount)
7330a2aa8a2bSBram Moolenaar 		return INVALID_QFIDX;
733155b69264SBram Moolenaar 	    else if (action != ' ')
733200bf8cd2SBram Moolenaar 		*newlist = FALSE;	// use the specified list
733355b69264SBram Moolenaar 	}
733455b69264SBram Moolenaar 	else if (di->di_tv.v_type == VAR_STRING
7335a0ca7d00SBram Moolenaar 		&& di->di_tv.vval.v_string != NULL
733655b69264SBram Moolenaar 		&& STRCMP(di->di_tv.vval.v_string, "$") == 0)
73376a8958dbSBram Moolenaar 	{
7338019dfe68SBram Moolenaar 	    if (!qf_stack_empty(qi))
7339875feea6SBram Moolenaar 		qf_idx = qi->qf_listcount - 1;
7340a2aa8a2bSBram Moolenaar 	    else if (*newlist)
734155b69264SBram Moolenaar 		qf_idx = 0;
734255b69264SBram Moolenaar 	    else
7343a2aa8a2bSBram Moolenaar 		return INVALID_QFIDX;
73446a8958dbSBram Moolenaar 	}
7345d823fa91SBram Moolenaar 	else
7346a2aa8a2bSBram Moolenaar 	    return INVALID_QFIDX;
73472b529bb6SBram Moolenaar     }
73482b529bb6SBram Moolenaar 
7349a2aa8a2bSBram Moolenaar     if (!*newlist && (di = dict_find(what, (char_u *)"id", -1)) != NULL)
7350a539f4f1SBram Moolenaar     {
735100bf8cd2SBram Moolenaar 	// Use the quickfix/location list with the specified id
7352a2aa8a2bSBram Moolenaar 	if (di->di_tv.v_type != VAR_NUMBER)
7353a2aa8a2bSBram Moolenaar 	    return INVALID_QFIDX;
7354a2aa8a2bSBram Moolenaar 
7355a2aa8a2bSBram Moolenaar 	return qf_id2nr(qi, di->di_tv.vval.v_number);
7356a539f4f1SBram Moolenaar     }
7357a2aa8a2bSBram Moolenaar 
7358a2aa8a2bSBram Moolenaar     return qf_idx;
7359a2aa8a2bSBram Moolenaar }
7360a2aa8a2bSBram Moolenaar 
7361a2aa8a2bSBram Moolenaar /*
7362a2aa8a2bSBram Moolenaar  * Set the quickfix list title.
7363a2aa8a2bSBram Moolenaar  */
7364a2aa8a2bSBram Moolenaar     static int
qf_setprop_title(qf_info_T * qi,int qf_idx,dict_T * what,dictitem_T * di)7365a2aa8a2bSBram Moolenaar qf_setprop_title(qf_info_T *qi, int qf_idx, dict_T *what, dictitem_T *di)
7366a2aa8a2bSBram Moolenaar {
73670398e00aSBram Moolenaar     qf_list_T	*qfl = qf_get_list(qi, qf_idx);
7368108e7b42SBram Moolenaar 
7369a2aa8a2bSBram Moolenaar     if (di->di_tv.v_type != VAR_STRING)
7370a539f4f1SBram Moolenaar 	return FAIL;
7371a539f4f1SBram Moolenaar 
7372108e7b42SBram Moolenaar     vim_free(qfl->qf_title);
73738f66717aSBram Moolenaar     qfl->qf_title = dict_get_string(what, (char_u *)"title", TRUE);
7374d823fa91SBram Moolenaar     if (qf_idx == qi->qf_curlist)
7375d823fa91SBram Moolenaar 	qf_update_win_titlevar(qi);
7376a2aa8a2bSBram Moolenaar 
7377a2aa8a2bSBram Moolenaar     return OK;
7378d823fa91SBram Moolenaar }
737936538225SBram Moolenaar 
7380a2aa8a2bSBram Moolenaar /*
7381a2aa8a2bSBram Moolenaar  * Set quickfix list items/entries.
7382a2aa8a2bSBram Moolenaar  */
7383a2aa8a2bSBram Moolenaar     static int
qf_setprop_items(qf_info_T * qi,int qf_idx,dictitem_T * di,int action)7384a2aa8a2bSBram Moolenaar qf_setprop_items(qf_info_T *qi, int qf_idx, dictitem_T *di, int action)
73856a8958dbSBram Moolenaar {
7386a2aa8a2bSBram Moolenaar     int		retval = FAIL;
7387a2aa8a2bSBram Moolenaar     char_u	*title_save;
73886a8958dbSBram Moolenaar 
7389a2aa8a2bSBram Moolenaar     if (di->di_tv.v_type != VAR_LIST)
7390a2aa8a2bSBram Moolenaar 	return FAIL;
7391a2aa8a2bSBram Moolenaar 
7392a2aa8a2bSBram Moolenaar     title_save = vim_strsave(qi->qf_lists[qf_idx].qf_title);
73936a8958dbSBram Moolenaar     retval = qf_add_entries(qi, qf_idx, di->di_tv.vval.v_list,
73946a8958dbSBram Moolenaar 	    title_save, action == ' ' ? 'a' : action);
73956a8958dbSBram Moolenaar     vim_free(title_save);
7396a2aa8a2bSBram Moolenaar 
7397a2aa8a2bSBram Moolenaar     return retval;
73986a8958dbSBram Moolenaar }
7399d823fa91SBram Moolenaar 
7400a2aa8a2bSBram Moolenaar /*
7401a2aa8a2bSBram Moolenaar  * Set quickfix list items/entries from a list of lines.
7402a2aa8a2bSBram Moolenaar  */
7403a2aa8a2bSBram Moolenaar     static int
qf_setprop_items_from_lines(qf_info_T * qi,int qf_idx,dict_T * what,dictitem_T * di,int action)7404a2aa8a2bSBram Moolenaar qf_setprop_items_from_lines(
7405a2aa8a2bSBram Moolenaar 	qf_info_T	*qi,
7406a2aa8a2bSBram Moolenaar 	int		qf_idx,
7407a2aa8a2bSBram Moolenaar 	dict_T		*what,
7408a2aa8a2bSBram Moolenaar 	dictitem_T	*di,
7409a2aa8a2bSBram Moolenaar 	int		action)
741036538225SBram Moolenaar {
7411a2aa8a2bSBram Moolenaar     char_u	*errorformat = p_efm;
7412a2aa8a2bSBram Moolenaar     dictitem_T	*efm_di;
7413a2aa8a2bSBram Moolenaar     int		retval = FAIL;
7414a2aa8a2bSBram Moolenaar 
741500bf8cd2SBram Moolenaar     // Use the user supplied errorformat settings (if present)
7416a2aa8a2bSBram Moolenaar     if ((efm_di = dict_find(what, (char_u *)"efm", -1)) != NULL)
7417a2aa8a2bSBram Moolenaar     {
7418a2aa8a2bSBram Moolenaar 	if (efm_di->di_tv.v_type != VAR_STRING ||
7419a2aa8a2bSBram Moolenaar 		efm_di->di_tv.vval.v_string == NULL)
742036538225SBram Moolenaar 	    return FAIL;
7421a2aa8a2bSBram Moolenaar 	errorformat = efm_di->di_tv.vval.v_string;
742236538225SBram Moolenaar     }
742336538225SBram Moolenaar 
742400bf8cd2SBram Moolenaar     // Only a List value is supported
7425a2aa8a2bSBram Moolenaar     if (di->di_tv.v_type != VAR_LIST || di->di_tv.vval.v_list == NULL)
7426a2aa8a2bSBram Moolenaar 	return FAIL;
7427a2aa8a2bSBram Moolenaar 
7428ae338338SBram Moolenaar     if (action == 'r')
7429fe15b7dfSBram Moolenaar 	qf_free_items(&qi->qf_lists[qf_idx]);
743036538225SBram Moolenaar     if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat,
7431287153c5SBram Moolenaar 		FALSE, (linenr_T)0, (linenr_T)0, NULL, NULL) >= 0)
7432ae338338SBram Moolenaar 	retval = OK;
7433a2aa8a2bSBram Moolenaar 
7434a2aa8a2bSBram Moolenaar     return retval;
7435ae338338SBram Moolenaar }
7436ae338338SBram Moolenaar 
7437a2aa8a2bSBram Moolenaar /*
7438a2aa8a2bSBram Moolenaar  * Set quickfix list context.
7439a2aa8a2bSBram Moolenaar  */
7440a2aa8a2bSBram Moolenaar     static int
qf_setprop_context(qf_list_T * qfl,dictitem_T * di)7441fe15b7dfSBram Moolenaar qf_setprop_context(qf_list_T *qfl, dictitem_T *di)
74428f77c5a4SBram Moolenaar {
74438f77c5a4SBram Moolenaar     typval_T	*ctx;
7444875feea6SBram Moolenaar 
7445fe15b7dfSBram Moolenaar     free_tv(qfl->qf_ctx);
74468f77c5a4SBram Moolenaar     ctx =  alloc_tv();
74478f77c5a4SBram Moolenaar     if (ctx != NULL)
74488f77c5a4SBram Moolenaar 	copy_tv(&di->di_tv, ctx);
7449fe15b7dfSBram Moolenaar     qfl->qf_ctx = ctx;
7450a2aa8a2bSBram Moolenaar 
7451a2aa8a2bSBram Moolenaar     return OK;
74528f77c5a4SBram Moolenaar }
74538f77c5a4SBram Moolenaar 
7454a2aa8a2bSBram Moolenaar /*
74555b69c22fSBram Moolenaar  * Set the current index in the specified quickfix list
74565b69c22fSBram Moolenaar  */
74575b69c22fSBram Moolenaar     static int
qf_setprop_curidx(qf_info_T * qi,qf_list_T * qfl,dictitem_T * di)74585b69c22fSBram Moolenaar qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl, dictitem_T *di)
74595b69c22fSBram Moolenaar {
74605b69c22fSBram Moolenaar     int		denote = FALSE;
74615b69c22fSBram Moolenaar     int		newidx;
74625b69c22fSBram Moolenaar     int		old_qfidx;
74635b69c22fSBram Moolenaar     qfline_T	*qf_ptr;
74645b69c22fSBram Moolenaar 
74655b69c22fSBram Moolenaar     // If the specified index is '$', then use the last entry
74665b69c22fSBram Moolenaar     if (di->di_tv.v_type == VAR_STRING
74675b69c22fSBram Moolenaar 	    && di->di_tv.vval.v_string != NULL
74685b69c22fSBram Moolenaar 	    && STRCMP(di->di_tv.vval.v_string, "$") == 0)
74695b69c22fSBram Moolenaar 	newidx = qfl->qf_count;
74705b69c22fSBram Moolenaar     else
74715b69c22fSBram Moolenaar     {
74725b69c22fSBram Moolenaar 	// Otherwise use the specified index
74735b69c22fSBram Moolenaar 	newidx = tv_get_number_chk(&di->di_tv, &denote);
74745b69c22fSBram Moolenaar 	if (denote)
74755b69c22fSBram Moolenaar 	    return FAIL;
74765b69c22fSBram Moolenaar     }
74775b69c22fSBram Moolenaar 
74785b69c22fSBram Moolenaar     if (newidx < 1)		// sanity check
74795b69c22fSBram Moolenaar 	return FAIL;
74805b69c22fSBram Moolenaar     if (newidx > qfl->qf_count)
74815b69c22fSBram Moolenaar 	newidx = qfl->qf_count;
74825b69c22fSBram Moolenaar 
74835b69c22fSBram Moolenaar     old_qfidx = qfl->qf_index;
74845b69c22fSBram Moolenaar     qf_ptr = get_nth_entry(qfl, newidx, &newidx);
74855b69c22fSBram Moolenaar     if (qf_ptr == NULL)
74865b69c22fSBram Moolenaar 	return FAIL;
74875b69c22fSBram Moolenaar     qfl->qf_ptr = qf_ptr;
74885b69c22fSBram Moolenaar     qfl->qf_index = newidx;
74895b69c22fSBram Moolenaar 
74905b69c22fSBram Moolenaar     // If the current list is modified and it is displayed in the quickfix
74915b69c22fSBram Moolenaar     // window, then Update it.
74924aa47b28SBram Moolenaar     if (qf_get_curlist(qi)->qf_id == qfl->qf_id)
74935b69c22fSBram Moolenaar 	qf_win_pos_update(qi, old_qfidx);
74945b69c22fSBram Moolenaar 
74955b69c22fSBram Moolenaar     return OK;
74965b69c22fSBram Moolenaar }
74975b69c22fSBram Moolenaar 
74985b69c22fSBram Moolenaar /*
7499858ba06dSBram Moolenaar  * Set the current index in the specified quickfix list
7500858ba06dSBram Moolenaar  */
7501858ba06dSBram Moolenaar     static int
qf_setprop_qftf(qf_info_T * qi UNUSED,qf_list_T * qfl,dictitem_T * di)7502858ba06dSBram Moolenaar qf_setprop_qftf(qf_info_T *qi UNUSED, qf_list_T *qfl, dictitem_T *di)
7503858ba06dSBram Moolenaar {
7504d43906d2SBram Moolenaar     callback_T	cb;
7505d43906d2SBram Moolenaar 
7506d43906d2SBram Moolenaar     free_callback(&qfl->qftf_cb);
7507d43906d2SBram Moolenaar     cb = get_callback(&di->di_tv);
7508d43906d2SBram Moolenaar     if (cb.cb_name != NULL && *cb.cb_name != NUL)
7509d43906d2SBram Moolenaar 	set_callback(&qfl->qftf_cb, &cb);
7510858ba06dSBram Moolenaar 
7511858ba06dSBram Moolenaar     return OK;
7512858ba06dSBram Moolenaar }
7513858ba06dSBram Moolenaar 
7514858ba06dSBram Moolenaar /*
7515a2aa8a2bSBram Moolenaar  * Set quickfix/location list properties (title, items, context).
7516a2aa8a2bSBram Moolenaar  * Also used to add items from parsing a list of lines.
75177a2b0e55SBram Moolenaar  * Used by the setqflist() and setloclist() Vim script functions.
7518a2aa8a2bSBram Moolenaar  */
7519a2aa8a2bSBram Moolenaar     static int
qf_set_properties(qf_info_T * qi,dict_T * what,int action,char_u * title)7520a2aa8a2bSBram Moolenaar qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title)
7521a2aa8a2bSBram Moolenaar {
7522a2aa8a2bSBram Moolenaar     dictitem_T	*di;
7523a2aa8a2bSBram Moolenaar     int		retval = FAIL;
7524a2aa8a2bSBram Moolenaar     int		qf_idx;
7525a2aa8a2bSBram Moolenaar     int		newlist = FALSE;
7526108e7b42SBram Moolenaar     qf_list_T	*qfl;
7527a2aa8a2bSBram Moolenaar 
7528019dfe68SBram Moolenaar     if (action == ' ' || qf_stack_empty(qi))
7529a2aa8a2bSBram Moolenaar 	newlist = TRUE;
7530a2aa8a2bSBram Moolenaar 
7531a2aa8a2bSBram Moolenaar     qf_idx = qf_setprop_get_qfidx(qi, what, action, &newlist);
753200bf8cd2SBram Moolenaar     if (qf_idx == INVALID_QFIDX)	// List not found
7533a2aa8a2bSBram Moolenaar 	return FAIL;
7534a2aa8a2bSBram Moolenaar 
7535a2aa8a2bSBram Moolenaar     if (newlist)
7536a2aa8a2bSBram Moolenaar     {
7537a2aa8a2bSBram Moolenaar 	qi->qf_curlist = qf_idx;
7538a2aa8a2bSBram Moolenaar 	qf_new_list(qi, title);
7539a2aa8a2bSBram Moolenaar 	qf_idx = qi->qf_curlist;
7540a2aa8a2bSBram Moolenaar     }
7541a2aa8a2bSBram Moolenaar 
75420398e00aSBram Moolenaar     qfl = qf_get_list(qi, qf_idx);
7543a2aa8a2bSBram Moolenaar     if ((di = dict_find(what, (char_u *)"title", -1)) != NULL)
7544a2aa8a2bSBram Moolenaar 	retval = qf_setprop_title(qi, qf_idx, what, di);
7545a2aa8a2bSBram Moolenaar     if ((di = dict_find(what, (char_u *)"items", -1)) != NULL)
7546a2aa8a2bSBram Moolenaar 	retval = qf_setprop_items(qi, qf_idx, di, action);
7547a2aa8a2bSBram Moolenaar     if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL)
7548a2aa8a2bSBram Moolenaar 	retval = qf_setprop_items_from_lines(qi, qf_idx, what, di, action);
7549a2aa8a2bSBram Moolenaar     if ((di = dict_find(what, (char_u *)"context", -1)) != NULL)
7550108e7b42SBram Moolenaar 	retval = qf_setprop_context(qfl, di);
75515b69c22fSBram Moolenaar     if ((di = dict_find(what, (char_u *)"idx", -1)) != NULL)
75525b69c22fSBram Moolenaar 	retval = qf_setprop_curidx(qi, qfl, di);
7553858ba06dSBram Moolenaar     if ((di = dict_find(what, (char_u *)"quickfixtextfunc", -1)) != NULL)
7554858ba06dSBram Moolenaar 	retval = qf_setprop_qftf(qi, qfl, di);
7555a2aa8a2bSBram Moolenaar 
7556287153c5SBram Moolenaar     if (newlist || retval == OK)
7557108e7b42SBram Moolenaar 	qf_list_changed(qfl);
7558287153c5SBram Moolenaar     if (newlist)
7559287153c5SBram Moolenaar 	qf_update_buffer(qi, NULL);
7560b254af31SBram Moolenaar 
7561d823fa91SBram Moolenaar     return retval;
7562d823fa91SBram Moolenaar }
7563d823fa91SBram Moolenaar 
756469f40be6SBram Moolenaar /*
756569f40be6SBram Moolenaar  * Free the entire quickfix/location list stack.
756669f40be6SBram Moolenaar  * If the quickfix/location list window is open, then clear it.
756769f40be6SBram Moolenaar  */
7568b6fa30ccSBram Moolenaar     static void
qf_free_stack(win_T * wp,qf_info_T * qi)7569b6fa30ccSBram Moolenaar qf_free_stack(win_T *wp, qf_info_T *qi)
7570b6fa30ccSBram Moolenaar {
757169f40be6SBram Moolenaar     win_T	*qfwin = qf_find_win(qi);
757269f40be6SBram Moolenaar     win_T	*llwin = NULL;
757369f40be6SBram Moolenaar 
757469f40be6SBram Moolenaar     if (qfwin != NULL)
757569f40be6SBram Moolenaar     {
757600bf8cd2SBram Moolenaar 	// If the quickfix/location list window is open, then clear it
757769f40be6SBram Moolenaar 	if (qi->qf_curlist < qi->qf_listcount)
75784aa47b28SBram Moolenaar 	    qf_free(qf_get_curlist(qi));
757969f40be6SBram Moolenaar 	qf_update_buffer(qi, NULL);
758069f40be6SBram Moolenaar     }
758169f40be6SBram Moolenaar 
758269f40be6SBram Moolenaar     if (wp != NULL && IS_LL_WINDOW(wp))
758369f40be6SBram Moolenaar     {
758400bf8cd2SBram Moolenaar 	// If in the location list window, then use the non-location list
758500bf8cd2SBram Moolenaar 	// window with this location list (if present)
7586ee8188fcSBram Moolenaar 	llwin = qf_find_win_with_loclist(qi);
758769f40be6SBram Moolenaar 	if (llwin != NULL)
758869f40be6SBram Moolenaar 	    wp = llwin;
758969f40be6SBram Moolenaar     }
759069f40be6SBram Moolenaar 
7591b6fa30ccSBram Moolenaar     qf_free_all(wp);
7592b6fa30ccSBram Moolenaar     if (wp == NULL)
7593b6fa30ccSBram Moolenaar     {
759400bf8cd2SBram Moolenaar 	// quickfix list
7595b6fa30ccSBram Moolenaar 	qi->qf_curlist = 0;
7596b6fa30ccSBram Moolenaar 	qi->qf_listcount = 0;
7597b6fa30ccSBram Moolenaar     }
7598ee8188fcSBram Moolenaar     else if (qfwin != NULL)
759969f40be6SBram Moolenaar     {
760000bf8cd2SBram Moolenaar 	// If the location list window is open, then create a new empty
760100bf8cd2SBram Moolenaar 	// location list
76022d67d307SBram Moolenaar 	qf_info_T *new_ll = qf_alloc_stack(QFLT_LOCATION);
760395946f12SBram Moolenaar 
760495946f12SBram Moolenaar 	if (new_ll != NULL)
760595946f12SBram Moolenaar 	{
7606ee8188fcSBram Moolenaar 	    new_ll->qf_bufnr = qfwin->w_buffer->b_fnum;
760799895eacSBram Moolenaar 
760800bf8cd2SBram Moolenaar 	    // first free the list reference in the location list window
7609ee8188fcSBram Moolenaar 	    ll_free_all(&qfwin->w_llist_ref);
7610d788f6feSBram Moolenaar 
7611ee8188fcSBram Moolenaar 	    qfwin->w_llist_ref = new_ll;
7612ee8188fcSBram Moolenaar 	    if (wp != qfwin)
76134aa47b28SBram Moolenaar 		win_set_loclist(wp, new_ll);
761469f40be6SBram Moolenaar 	}
7615b6fa30ccSBram Moolenaar     }
761695946f12SBram Moolenaar }
7617b6fa30ccSBram Moolenaar 
7618d823fa91SBram Moolenaar /*
7619d823fa91SBram Moolenaar  * Populate the quickfix list with the items supplied in the list
7620d823fa91SBram Moolenaar  * of dictionaries. "title" will be copied to w:quickfix_title.
7621d823fa91SBram Moolenaar  * "action" is 'a' for add, 'r' for replace.  Otherwise create a new list.
762290049492SBram Moolenaar  * When "what" is not NULL then only set some properties.
7623d823fa91SBram Moolenaar  */
7624d823fa91SBram Moolenaar     int
set_errorlist(win_T * wp,list_T * list,int action,char_u * title,dict_T * what)7625d823fa91SBram Moolenaar set_errorlist(
7626d823fa91SBram Moolenaar 	win_T	*wp,
7627d823fa91SBram Moolenaar 	list_T	*list,
7628d823fa91SBram Moolenaar 	int	action,
7629d823fa91SBram Moolenaar 	char_u	*title,
7630d823fa91SBram Moolenaar 	dict_T	*what)
7631d823fa91SBram Moolenaar {
7632d823fa91SBram Moolenaar     qf_info_T	*qi = &ql_info;
7633d823fa91SBram Moolenaar     int		retval = OK;
7634d823fa91SBram Moolenaar 
7635d823fa91SBram Moolenaar     if (wp != NULL)
7636d823fa91SBram Moolenaar     {
7637d823fa91SBram Moolenaar 	qi = ll_get_or_alloc_list(wp);
7638d823fa91SBram Moolenaar 	if (qi == NULL)
7639d823fa91SBram Moolenaar 	    return FAIL;
7640d823fa91SBram Moolenaar     }
7641d823fa91SBram Moolenaar 
7642b6fa30ccSBram Moolenaar     if (action == 'f')
7643b6fa30ccSBram Moolenaar     {
764400bf8cd2SBram Moolenaar 	// Free the entire quickfix or location list stack
7645b6fa30ccSBram Moolenaar 	qf_free_stack(wp, qi);
76469f84ded3SBram Moolenaar 	return OK;
7647b6fa30ccSBram Moolenaar     }
76489f84ded3SBram Moolenaar 
7649be7a50c2SBram Moolenaar     // A dict argument cannot be specified with a non-empty list argument
765090049492SBram Moolenaar     if (list->lv_len != 0 && what != NULL)
7651be7a50c2SBram Moolenaar     {
7652be7a50c2SBram Moolenaar 	semsg(_(e_invarg2),
7653be7a50c2SBram Moolenaar 			 _("cannot have both a list and a \"what\" argument"));
7654be7a50c2SBram Moolenaar 	return FAIL;
7655be7a50c2SBram Moolenaar     }
7656be7a50c2SBram Moolenaar 
76579f84ded3SBram Moolenaar     incr_quickfix_busy();
76589f84ded3SBram Moolenaar 
76599f84ded3SBram Moolenaar     if (what != NULL)
7660ae338338SBram Moolenaar 	retval = qf_set_properties(qi, what, action, title);
7661d823fa91SBram Moolenaar     else
7662b254af31SBram Moolenaar     {
7663a3921f48SBram Moolenaar 	retval = qf_add_entries(qi, qi->qf_curlist, list, title, action);
7664b254af31SBram Moolenaar 	if (retval == OK)
76654aa47b28SBram Moolenaar 	    qf_list_changed(qf_get_curlist(qi));
7666b254af31SBram Moolenaar     }
7667d823fa91SBram Moolenaar 
76689f84ded3SBram Moolenaar     decr_quickfix_busy();
76699f84ded3SBram Moolenaar 
7670d823fa91SBram Moolenaar     return retval;
7671d823fa91SBram Moolenaar }
76728f77c5a4SBram Moolenaar 
767318cebf44SBram Moolenaar /*
767418cebf44SBram Moolenaar  * Mark the context as in use for all the lists in a quickfix stack.
767518cebf44SBram Moolenaar  */
76768f77c5a4SBram Moolenaar     static int
mark_quickfix_ctx(qf_info_T * qi,int copyID)76778f77c5a4SBram Moolenaar mark_quickfix_ctx(qf_info_T *qi, int copyID)
76788f77c5a4SBram Moolenaar {
76798f77c5a4SBram Moolenaar     int		i;
76808f77c5a4SBram Moolenaar     int		abort = FALSE;
76818f77c5a4SBram Moolenaar     typval_T	*ctx;
76828f77c5a4SBram Moolenaar 
76838f77c5a4SBram Moolenaar     for (i = 0; i < LISTCOUNT && !abort; ++i)
76848f77c5a4SBram Moolenaar     {
76858f77c5a4SBram Moolenaar 	ctx = qi->qf_lists[i].qf_ctx;
768655b69264SBram Moolenaar 	if (ctx != NULL && ctx->v_type != VAR_NUMBER
768755b69264SBram Moolenaar 		&& ctx->v_type != VAR_STRING && ctx->v_type != VAR_FLOAT)
76888f77c5a4SBram Moolenaar 	    abort = set_ref_in_item(ctx, copyID, NULL, NULL);
76898f77c5a4SBram Moolenaar     }
76908f77c5a4SBram Moolenaar 
76918f77c5a4SBram Moolenaar     return abort;
76928f77c5a4SBram Moolenaar }
76938f77c5a4SBram Moolenaar 
76948f77c5a4SBram Moolenaar /*
76958f77c5a4SBram Moolenaar  * Mark the context of the quickfix list and the location lists (if present) as
7696353eeeacSBram Moolenaar  * "in use". So that garbage collection doesn't free the context.
76978f77c5a4SBram Moolenaar  */
76988f77c5a4SBram Moolenaar     int
set_ref_in_quickfix(int copyID)76998f77c5a4SBram Moolenaar set_ref_in_quickfix(int copyID)
77008f77c5a4SBram Moolenaar {
77018f77c5a4SBram Moolenaar     int		abort = FALSE;
77028f77c5a4SBram Moolenaar     tabpage_T	*tp;
77038f77c5a4SBram Moolenaar     win_T	*win;
77048f77c5a4SBram Moolenaar 
77058f77c5a4SBram Moolenaar     abort = mark_quickfix_ctx(&ql_info, copyID);
77068f77c5a4SBram Moolenaar     if (abort)
77078f77c5a4SBram Moolenaar 	return abort;
77088f77c5a4SBram Moolenaar 
77098f77c5a4SBram Moolenaar     FOR_ALL_TAB_WINDOWS(tp, win)
77108f77c5a4SBram Moolenaar     {
77118f77c5a4SBram Moolenaar 	if (win->w_llist != NULL)
77128f77c5a4SBram Moolenaar 	{
77138f77c5a4SBram Moolenaar 	    abort = mark_quickfix_ctx(win->w_llist, copyID);
77148f77c5a4SBram Moolenaar 	    if (abort)
77158f77c5a4SBram Moolenaar 		return abort;
77168f77c5a4SBram Moolenaar 	}
771712237448SBram Moolenaar 	if (IS_LL_WINDOW(win) && (win->w_llist_ref->qf_refcount == 1))
771812237448SBram Moolenaar 	{
771900bf8cd2SBram Moolenaar 	    // In a location list window and none of the other windows is
772000bf8cd2SBram Moolenaar 	    // referring to this location list. Mark the location list
772100bf8cd2SBram Moolenaar 	    // context as still in use.
772212237448SBram Moolenaar 	    abort = mark_quickfix_ctx(win->w_llist_ref, copyID);
772312237448SBram Moolenaar 	    if (abort)
772412237448SBram Moolenaar 		return abort;
772512237448SBram Moolenaar 	}
77268f77c5a4SBram Moolenaar     }
77278f77c5a4SBram Moolenaar 
77288f77c5a4SBram Moolenaar     return abort;
77298f77c5a4SBram Moolenaar }
773005159a0cSBram Moolenaar #endif
773105159a0cSBram Moolenaar 
773281695250SBram Moolenaar /*
7733a16123a6SBram Moolenaar  * Return the autocmd name for the :cbuffer Ex commands
7734a16123a6SBram Moolenaar  */
7735a16123a6SBram Moolenaar     static char_u *
cbuffer_get_auname(cmdidx_T cmdidx)7736a16123a6SBram Moolenaar cbuffer_get_auname(cmdidx_T cmdidx)
7737a16123a6SBram Moolenaar {
7738a16123a6SBram Moolenaar     switch (cmdidx)
7739a16123a6SBram Moolenaar     {
7740a16123a6SBram Moolenaar 	case CMD_cbuffer:	return (char_u *)"cbuffer";
7741a16123a6SBram Moolenaar 	case CMD_cgetbuffer:	return (char_u *)"cgetbuffer";
7742a16123a6SBram Moolenaar 	case CMD_caddbuffer:	return (char_u *)"caddbuffer";
7743a16123a6SBram Moolenaar 	case CMD_lbuffer:	return (char_u *)"lbuffer";
7744a16123a6SBram Moolenaar 	case CMD_lgetbuffer:	return (char_u *)"lgetbuffer";
7745a16123a6SBram Moolenaar 	case CMD_laddbuffer:	return (char_u *)"laddbuffer";
7746a16123a6SBram Moolenaar 	default:		return NULL;
7747a16123a6SBram Moolenaar     }
7748a16123a6SBram Moolenaar }
7749a16123a6SBram Moolenaar 
7750a16123a6SBram Moolenaar /*
7751a16123a6SBram Moolenaar  * Process and validate the arguments passed to the :cbuffer, :caddbuffer,
7752a16123a6SBram Moolenaar  * :cgetbuffer, :lbuffer, :laddbuffer, :lgetbuffer Ex commands.
7753a16123a6SBram Moolenaar  */
7754a16123a6SBram Moolenaar     static int
cbuffer_process_args(exarg_T * eap,buf_T ** bufp,linenr_T * line1,linenr_T * line2)7755a16123a6SBram Moolenaar cbuffer_process_args(
7756a16123a6SBram Moolenaar 	exarg_T		*eap,
7757a16123a6SBram Moolenaar 	buf_T		**bufp,
7758a16123a6SBram Moolenaar 	linenr_T	*line1,
7759a16123a6SBram Moolenaar 	linenr_T	*line2)
7760a16123a6SBram Moolenaar {
7761a16123a6SBram Moolenaar     buf_T	*buf = NULL;
7762a16123a6SBram Moolenaar 
7763a16123a6SBram Moolenaar     if (*eap->arg == NUL)
7764a16123a6SBram Moolenaar 	buf = curbuf;
7765a16123a6SBram Moolenaar     else if (*skipwhite(skipdigits(eap->arg)) == NUL)
7766a16123a6SBram Moolenaar 	buf = buflist_findnr(atoi((char *)eap->arg));
7767a16123a6SBram Moolenaar 
7768a16123a6SBram Moolenaar     if (buf == NULL)
7769a16123a6SBram Moolenaar     {
7770a16123a6SBram Moolenaar 	emsg(_(e_invarg));
7771a16123a6SBram Moolenaar 	return FAIL;
7772a16123a6SBram Moolenaar     }
7773a16123a6SBram Moolenaar 
7774a16123a6SBram Moolenaar     if (buf->b_ml.ml_mfp == NULL)
7775a16123a6SBram Moolenaar     {
7776a16123a6SBram Moolenaar 	emsg(_("E681: Buffer is not loaded"));
7777a16123a6SBram Moolenaar 	return FAIL;
7778a16123a6SBram Moolenaar     }
7779a16123a6SBram Moolenaar 
7780a16123a6SBram Moolenaar     if (eap->addr_count == 0)
7781a16123a6SBram Moolenaar     {
7782a16123a6SBram Moolenaar 	eap->line1 = 1;
7783a16123a6SBram Moolenaar 	eap->line2 = buf->b_ml.ml_line_count;
7784a16123a6SBram Moolenaar     }
7785a16123a6SBram Moolenaar 
7786a16123a6SBram Moolenaar     if (eap->line1 < 1 || eap->line1 > buf->b_ml.ml_line_count
7787a16123a6SBram Moolenaar 	    || eap->line2 < 1 || eap->line2 > buf->b_ml.ml_line_count)
7788a16123a6SBram Moolenaar     {
7789108010aaSBram Moolenaar 	emsg(_(e_invalid_range));
7790a16123a6SBram Moolenaar 	return FAIL;
7791a16123a6SBram Moolenaar     }
7792a16123a6SBram Moolenaar 
7793a16123a6SBram Moolenaar     *line1 = eap->line1;
7794a16123a6SBram Moolenaar     *line2 = eap->line2;
7795a16123a6SBram Moolenaar     *bufp = buf;
7796a16123a6SBram Moolenaar 
7797a16123a6SBram Moolenaar     return OK;
7798a16123a6SBram Moolenaar }
7799a16123a6SBram Moolenaar 
7800a16123a6SBram Moolenaar /*
780186b68359SBram Moolenaar  * ":[range]cbuffer [bufnr]" command.
7802a6557605SBram Moolenaar  * ":[range]caddbuffer [bufnr]" command.
7803db552d60SBram Moolenaar  * ":[range]cgetbuffer [bufnr]" command.
7804d12f5c17SBram Moolenaar  * ":[range]lbuffer [bufnr]" command.
7805a6557605SBram Moolenaar  * ":[range]laddbuffer [bufnr]" command.
7806db552d60SBram Moolenaar  * ":[range]lgetbuffer [bufnr]" command.
780786b68359SBram Moolenaar  */
780886b68359SBram Moolenaar     void
ex_cbuffer(exarg_T * eap)780905540976SBram Moolenaar ex_cbuffer(exarg_T *eap)
781086b68359SBram Moolenaar {
781186b68359SBram Moolenaar     buf_T	*buf = NULL;
781287f59b09SBram Moolenaar     qf_info_T	*qi;
781304c4ce65SBram Moolenaar     char_u	*au_name = NULL;
78141ed2276fSBram Moolenaar     int		res;
7815531b9a3aSBram Moolenaar     int_u	save_qfid;
7816531b9a3aSBram Moolenaar     win_T	*wp = NULL;
7817a16123a6SBram Moolenaar     char_u	*qf_title;
7818a16123a6SBram Moolenaar     linenr_T	line1;
7819a16123a6SBram Moolenaar     linenr_T	line2;
7820d12f5c17SBram Moolenaar 
7821a16123a6SBram Moolenaar     au_name = cbuffer_get_auname(eap->cmdidx);
782221662be2SBram Moolenaar     if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
782321662be2SBram Moolenaar 					curbuf->b_fname, TRUE, curbuf))
782404c4ce65SBram Moolenaar     {
782504c4ce65SBram Moolenaar #ifdef FEAT_EVAL
782621662be2SBram Moolenaar 	if (aborting())
782704c4ce65SBram Moolenaar 	    return;
782804c4ce65SBram Moolenaar #endif
782904c4ce65SBram Moolenaar     }
783004c4ce65SBram Moolenaar 
783100bf8cd2SBram Moolenaar     // Must come after autocommands.
783287f59b09SBram Moolenaar     qi = qf_cmd_get_or_alloc_stack(eap, &wp);
7833aaf6e43bSBram Moolenaar     if (qi == NULL)
7834aaf6e43bSBram Moolenaar 	return;
7835aaf6e43bSBram Moolenaar 
7836a16123a6SBram Moolenaar     if (cbuffer_process_args(eap, &buf, &line1, &line2) == FAIL)
7837a16123a6SBram Moolenaar 	return;
7838a16123a6SBram Moolenaar 
7839a16123a6SBram Moolenaar     qf_title = qf_cmdtitle(*eap->cmdlinep);
78407fd73200SBram Moolenaar 
78417fd73200SBram Moolenaar     if (buf->b_sfname)
78427fd73200SBram Moolenaar     {
78437fd73200SBram Moolenaar 	vim_snprintf((char *)IObuff, IOSIZE, "%s (%s)",
78447fd73200SBram Moolenaar 		(char *)qf_title, (char *)buf->b_sfname);
78457fd73200SBram Moolenaar 	qf_title = IObuff;
78467fd73200SBram Moolenaar     }
78477fd73200SBram Moolenaar 
78489f84ded3SBram Moolenaar     incr_quickfix_busy();
78499f84ded3SBram Moolenaar 
78501ed2276fSBram Moolenaar     res = qf_init_ext(qi, qi->qf_curlist, NULL, buf, NULL, p_efm,
7851db552d60SBram Moolenaar 	    (eap->cmdidx != CMD_caddbuffer
7852db552d60SBram Moolenaar 	     && eap->cmdidx != CMD_laddbuffer),
7853a16123a6SBram Moolenaar 	    line1, line2,
78541ed2276fSBram Moolenaar 	    qf_title, NULL);
78559f84ded3SBram Moolenaar     if (qf_stack_empty(qi))
78569f84ded3SBram Moolenaar     {
78579f84ded3SBram Moolenaar 	decr_quickfix_busy();
78589f84ded3SBram Moolenaar 	return;
78599f84ded3SBram Moolenaar     }
7860b254af31SBram Moolenaar     if (res >= 0)
78614aa47b28SBram Moolenaar 	qf_list_changed(qf_get_curlist(qi));
7862531b9a3aSBram Moolenaar 
7863531b9a3aSBram Moolenaar     // Remember the current quickfix list identifier, so that we can
7864531b9a3aSBram Moolenaar     // check for autocommands changing the current quickfix list.
78654aa47b28SBram Moolenaar     save_qfid = qf_get_curlist(qi)->qf_id;
786604c4ce65SBram Moolenaar     if (au_name != NULL)
7867600323b4SBram Moolenaar     {
7868600323b4SBram Moolenaar 	buf_T *curbuf_old = curbuf;
7869600323b4SBram Moolenaar 
7870a16123a6SBram Moolenaar 	apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname,
7871a16123a6SBram Moolenaar 								TRUE, curbuf);
7872600323b4SBram Moolenaar 	if (curbuf != curbuf_old)
7873600323b4SBram Moolenaar 	    // Autocommands changed buffer, don't jump now, "qi" may
7874600323b4SBram Moolenaar 	    // be invalid.
7875600323b4SBram Moolenaar 	    res = 0;
7876600323b4SBram Moolenaar     }
7877531b9a3aSBram Moolenaar     // Jump to the first error for a new list and if autocmds didn't
7878531b9a3aSBram Moolenaar     // free the list.
78791ed2276fSBram Moolenaar     if (res > 0 && (eap->cmdidx == CMD_cbuffer ||
7880531b9a3aSBram Moolenaar 		eap->cmdidx == CMD_lbuffer)
7881531b9a3aSBram Moolenaar 	    && qflist_valid(wp, save_qfid))
78828d8a65e3SBram Moolenaar 	// display the first error
78838d8a65e3SBram Moolenaar 	qf_jump_first(qi, save_qfid, eap->forceit);
78849f84ded3SBram Moolenaar 
78859f84ded3SBram Moolenaar     decr_quickfix_busy();
7886754b5608SBram Moolenaar }
7887a16123a6SBram Moolenaar 
7888a16123a6SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
7889a16123a6SBram Moolenaar /*
7890a16123a6SBram Moolenaar  * Return the autocmd name for the :cexpr Ex commands.
7891a16123a6SBram Moolenaar  */
78925f7d4c04SBram Moolenaar     char_u *
cexpr_get_auname(cmdidx_T cmdidx)7893a16123a6SBram Moolenaar cexpr_get_auname(cmdidx_T cmdidx)
7894a16123a6SBram Moolenaar {
7895a16123a6SBram Moolenaar     switch (cmdidx)
7896a16123a6SBram Moolenaar     {
7897a16123a6SBram Moolenaar 	case CMD_cexpr:	    return (char_u *)"cexpr";
7898a16123a6SBram Moolenaar 	case CMD_cgetexpr:  return (char_u *)"cgetexpr";
7899a16123a6SBram Moolenaar 	case CMD_caddexpr:  return (char_u *)"caddexpr";
7900a16123a6SBram Moolenaar 	case CMD_lexpr:	    return (char_u *)"lexpr";
7901a16123a6SBram Moolenaar 	case CMD_lgetexpr:  return (char_u *)"lgetexpr";
7902a16123a6SBram Moolenaar 	case CMD_laddexpr:  return (char_u *)"laddexpr";
7903a16123a6SBram Moolenaar 	default:	    return NULL;
790486b68359SBram Moolenaar     }
790586b68359SBram Moolenaar }
790686b68359SBram Moolenaar 
79075f7d4c04SBram Moolenaar     int
trigger_cexpr_autocmd(int cmdidx)79085f7d4c04SBram Moolenaar trigger_cexpr_autocmd(int cmdidx)
790987e25fdfSBram Moolenaar {
79105f7d4c04SBram Moolenaar     char_u	*au_name = cexpr_get_auname(cmdidx);
7911d12f5c17SBram Moolenaar 
791221662be2SBram Moolenaar     if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
791321662be2SBram Moolenaar 					       curbuf->b_fname, TRUE, curbuf))
791404c4ce65SBram Moolenaar     {
791521662be2SBram Moolenaar 	if (aborting())
79165f7d4c04SBram Moolenaar 	    return FAIL;
791704c4ce65SBram Moolenaar     }
79185f7d4c04SBram Moolenaar     return OK;
79195f7d4c04SBram Moolenaar }
79205f7d4c04SBram Moolenaar 
79215f7d4c04SBram Moolenaar     int
cexpr_core(exarg_T * eap,typval_T * tv)79225f7d4c04SBram Moolenaar cexpr_core(exarg_T *eap, typval_T *tv)
79235f7d4c04SBram Moolenaar {
79245f7d4c04SBram Moolenaar     qf_info_T	*qi;
79255f7d4c04SBram Moolenaar     win_T	*wp = NULL;
792604c4ce65SBram Moolenaar 
792787f59b09SBram Moolenaar     qi = qf_cmd_get_or_alloc_stack(eap, &wp);
79283c097226SBram Moolenaar     if (qi == NULL)
79295f7d4c04SBram Moolenaar 	return FAIL;
79303c097226SBram Moolenaar 
79314770d09aSBram Moolenaar     if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL)
79324770d09aSBram Moolenaar 	    || (tv->v_type == VAR_LIST && tv->vval.v_list != NULL))
79334770d09aSBram Moolenaar     {
79345f7d4c04SBram Moolenaar 	int	res;
79355f7d4c04SBram Moolenaar 	int_u	save_qfid;
79365f7d4c04SBram Moolenaar 	char_u	*au_name = cexpr_get_auname(eap->cmdidx);
79375f7d4c04SBram Moolenaar 
79389f84ded3SBram Moolenaar 	incr_quickfix_busy();
79391ed2276fSBram Moolenaar 	res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, tv, p_efm,
7940db552d60SBram Moolenaar 			(eap->cmdidx != CMD_caddexpr
7941db552d60SBram Moolenaar 			 && eap->cmdidx != CMD_laddexpr),
79428b62e310SBram Moolenaar 			     (linenr_T)0, (linenr_T)0,
79438b62e310SBram Moolenaar 			     qf_cmdtitle(*eap->cmdlinep), NULL);
79449f84ded3SBram Moolenaar 	if (qf_stack_empty(qi))
79459f84ded3SBram Moolenaar 	{
79469f84ded3SBram Moolenaar 	    decr_quickfix_busy();
79475f7d4c04SBram Moolenaar 	    return FAIL;
79489f84ded3SBram Moolenaar 	}
7949b254af31SBram Moolenaar 	if (res >= 0)
79504aa47b28SBram Moolenaar 	    qf_list_changed(qf_get_curlist(qi));
7951531b9a3aSBram Moolenaar 
7952531b9a3aSBram Moolenaar 	// Remember the current quickfix list identifier, so that we can
7953531b9a3aSBram Moolenaar 	// check for autocommands changing the current quickfix list.
79544aa47b28SBram Moolenaar 	save_qfid = qf_get_curlist(qi)->qf_id;
795504c4ce65SBram Moolenaar 	if (au_name != NULL)
795604c4ce65SBram Moolenaar 	    apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
795704c4ce65SBram Moolenaar 					    curbuf->b_fname, TRUE, curbuf);
7958531b9a3aSBram Moolenaar 
7959531b9a3aSBram Moolenaar 	// Jump to the first error for a new list and if autocmds didn't
7960531b9a3aSBram Moolenaar 	// free the list.
79615f7d4c04SBram Moolenaar 	if (res > 0 && (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr)
7962531b9a3aSBram Moolenaar 		&& qflist_valid(wp, save_qfid))
79638d8a65e3SBram Moolenaar 	    // display the first error
79648d8a65e3SBram Moolenaar 	    qf_jump_first(qi, save_qfid, eap->forceit);
79659f84ded3SBram Moolenaar 	decr_quickfix_busy();
79665f7d4c04SBram Moolenaar 	return OK;
79674770d09aSBram Moolenaar     }
79685f7d4c04SBram Moolenaar 
7969f9e3e09fSBram Moolenaar     emsg(_("E777: String or List expected"));
79705f7d4c04SBram Moolenaar     return FAIL;
79715f7d4c04SBram Moolenaar }
79725f7d4c04SBram Moolenaar 
79735f7d4c04SBram Moolenaar /*
79745f7d4c04SBram Moolenaar  * ":cexpr {expr}", ":cgetexpr {expr}", ":caddexpr {expr}" command.
79755f7d4c04SBram Moolenaar  * ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command.
79765f7d4c04SBram Moolenaar  * Also: ":caddexpr", ":cgetexpr", "laddexpr" and "laddexpr".
79775f7d4c04SBram Moolenaar  */
79785f7d4c04SBram Moolenaar     void
ex_cexpr(exarg_T * eap)79795f7d4c04SBram Moolenaar ex_cexpr(exarg_T *eap)
79805f7d4c04SBram Moolenaar {
79815f7d4c04SBram Moolenaar     typval_T	*tv;
79825f7d4c04SBram Moolenaar 
79835f7d4c04SBram Moolenaar     if (trigger_cexpr_autocmd(eap->cmdidx) == FAIL)
79845f7d4c04SBram Moolenaar 	return;
79855f7d4c04SBram Moolenaar 
79865f7d4c04SBram Moolenaar     // Evaluate the expression.  When the result is a string or a list we can
79875f7d4c04SBram Moolenaar     // use it to fill the errorlist.
79885f7d4c04SBram Moolenaar     tv = eval_expr(eap->arg, eap);
79895f7d4c04SBram Moolenaar     if (tv != NULL)
79905f7d4c04SBram Moolenaar     {
79915f7d4c04SBram Moolenaar 	(void)cexpr_core(eap, tv);
79924770d09aSBram Moolenaar 	free_tv(tv);
79934770d09aSBram Moolenaar     }
799487e25fdfSBram Moolenaar }
79951e015460SBram Moolenaar #endif
799687e25fdfSBram Moolenaar 
799787e25fdfSBram Moolenaar /*
79982225ebb4SBram Moolenaar  * Get the location list for ":lhelpgrep"
7999071d4279SBram Moolenaar  */
80002225ebb4SBram Moolenaar     static qf_info_T *
hgr_get_ll(int * new_ll)80012225ebb4SBram Moolenaar hgr_get_ll(int *new_ll)
8002071d4279SBram Moolenaar {
80038b6144bdSBram Moolenaar     win_T	*wp;
80042225ebb4SBram Moolenaar     qf_info_T	*qi;
8005071d4279SBram Moolenaar 
800600bf8cd2SBram Moolenaar     // If the current window is a help window, then use it
8007d28cc3f5SBram Moolenaar     if (bt_help(curwin->w_buffer))
8008d28cc3f5SBram Moolenaar 	wp = curwin;
8009d28cc3f5SBram Moolenaar     else
801000bf8cd2SBram Moolenaar 	// Find an existing help window
80117a2b0e55SBram Moolenaar 	wp = qf_find_help_win();
80128b6144bdSBram Moolenaar 
801300bf8cd2SBram Moolenaar     if (wp == NULL)	    // Help window not found
80148b6144bdSBram Moolenaar 	qi = NULL;
80158b6144bdSBram Moolenaar     else
80168b6144bdSBram Moolenaar 	qi = wp->w_llist;
80178b6144bdSBram Moolenaar 
80188b6144bdSBram Moolenaar     if (qi == NULL)
80198b6144bdSBram Moolenaar     {
802000bf8cd2SBram Moolenaar 	// Allocate a new location list for help text matches
80212d67d307SBram Moolenaar 	if ((qi = qf_alloc_stack(QFLT_LOCATION)) == NULL)
80222225ebb4SBram Moolenaar 	    return NULL;
80232225ebb4SBram Moolenaar 	*new_ll = TRUE;
80248b6144bdSBram Moolenaar     }
80258b6144bdSBram Moolenaar 
80262225ebb4SBram Moolenaar     return qi;
80272225ebb4SBram Moolenaar }
80282225ebb4SBram Moolenaar 
80292225ebb4SBram Moolenaar /*
80302225ebb4SBram Moolenaar  * Search for a pattern in a help file.
80312225ebb4SBram Moolenaar  */
80322225ebb4SBram Moolenaar     static void
hgr_search_file(qf_list_T * qfl,char_u * fname,vimconv_T * p_vc,regmatch_T * p_regmatch)80332225ebb4SBram Moolenaar hgr_search_file(
80349afe5e9cSBram Moolenaar 	qf_list_T *qfl,
80352225ebb4SBram Moolenaar 	char_u *fname,
80362225ebb4SBram Moolenaar 	vimconv_T *p_vc,
80372225ebb4SBram Moolenaar 	regmatch_T *p_regmatch)
80382225ebb4SBram Moolenaar {
80392225ebb4SBram Moolenaar     FILE	*fd;
80402225ebb4SBram Moolenaar     long	lnum;
804110b7b39bSBram Moolenaar 
80422225ebb4SBram Moolenaar     fd = mch_fopen((char *)fname, "r");
80432225ebb4SBram Moolenaar     if (fd == NULL)
80442225ebb4SBram Moolenaar 	return;
8045071d4279SBram Moolenaar 
8046071d4279SBram Moolenaar     lnum = 1;
8047071d4279SBram Moolenaar     while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int)
8048071d4279SBram Moolenaar     {
804910b7b39bSBram Moolenaar 	char_u    *line = IObuff;
8050a12a161bSBram Moolenaar 
805100bf8cd2SBram Moolenaar 	// Convert a line if 'encoding' is not utf-8 and
805200bf8cd2SBram Moolenaar 	// the line contains a non-ASCII character.
80532225ebb4SBram Moolenaar 	if (p_vc->vc_type != CONV_NONE
8054b6fa30ccSBram Moolenaar 		&& has_non_ascii(IObuff))
8055b6fa30ccSBram Moolenaar 	{
80562225ebb4SBram Moolenaar 	    line = string_convert(p_vc, IObuff, NULL);
805710b7b39bSBram Moolenaar 	    if (line == NULL)
805810b7b39bSBram Moolenaar 		line = IObuff;
805910b7b39bSBram Moolenaar 	}
806010b7b39bSBram Moolenaar 
80612225ebb4SBram Moolenaar 	if (vim_regexec(p_regmatch, line, (colnr_T)0))
8062071d4279SBram Moolenaar 	{
806310b7b39bSBram Moolenaar 	    int	l = (int)STRLEN(line);
8064071d4279SBram Moolenaar 
806500bf8cd2SBram Moolenaar 	    // remove trailing CR, LF, spaces, etc.
806610b7b39bSBram Moolenaar 	    while (l > 0 && line[l - 1] <= ' ')
806710b7b39bSBram Moolenaar 		line[--l] = NUL;
8068071d4279SBram Moolenaar 
80699afe5e9cSBram Moolenaar 	    if (qf_add_entry(qfl,
807000bf8cd2SBram Moolenaar 			NULL,	// dir
80712225ebb4SBram Moolenaar 			fname,
8072d76ce852SBram Moolenaar 			NULL,
807348b66fb5SBram Moolenaar 			0,
807410b7b39bSBram Moolenaar 			line,
8075071d4279SBram Moolenaar 			lnum,
80766864efa5Sthinca 			0,
80772225ebb4SBram Moolenaar 			(int)(p_regmatch->startp[0] - line)
807800bf8cd2SBram Moolenaar 			+ 1,	// col
80796864efa5Sthinca 			(int)(p_regmatch->endp[0] - line)
80806864efa5Sthinca 			+ 1,	// end_col
808100bf8cd2SBram Moolenaar 			FALSE,	// vis_col
808200bf8cd2SBram Moolenaar 			NULL,	// search pattern
808300bf8cd2SBram Moolenaar 			0,	// nr
808400bf8cd2SBram Moolenaar 			1,	// type
808500bf8cd2SBram Moolenaar 			TRUE	// valid
808695946f12SBram Moolenaar 			) == QF_FAIL)
8087071d4279SBram Moolenaar 	    {
8088071d4279SBram Moolenaar 		got_int = TRUE;
808910b7b39bSBram Moolenaar 		if (line != IObuff)
809010b7b39bSBram Moolenaar 		    vim_free(line);
8091071d4279SBram Moolenaar 		break;
8092071d4279SBram Moolenaar 	    }
8093071d4279SBram Moolenaar 	}
809410b7b39bSBram Moolenaar 	if (line != IObuff)
809510b7b39bSBram Moolenaar 	    vim_free(line);
8096071d4279SBram Moolenaar 	++lnum;
8097071d4279SBram Moolenaar 	line_breakcheck();
8098071d4279SBram Moolenaar     }
8099071d4279SBram Moolenaar     fclose(fd);
8100071d4279SBram Moolenaar }
81012225ebb4SBram Moolenaar 
81022225ebb4SBram Moolenaar /*
81032225ebb4SBram Moolenaar  * Search for a pattern in all the help files in the doc directory under
81042225ebb4SBram Moolenaar  * the given directory.
81052225ebb4SBram Moolenaar  */
81062225ebb4SBram Moolenaar     static void
hgr_search_files_in_dir(qf_list_T * qfl,char_u * dirname,regmatch_T * p_regmatch,vimconv_T * p_vc,char_u * lang)81072225ebb4SBram Moolenaar hgr_search_files_in_dir(
81089afe5e9cSBram Moolenaar 	qf_list_T *qfl,
81092225ebb4SBram Moolenaar 	char_u *dirname,
8110a12a161bSBram Moolenaar 	regmatch_T *p_regmatch,
8111a12a161bSBram Moolenaar 	vimconv_T *p_vc
81122225ebb4SBram Moolenaar #ifdef FEAT_MULTI_LANG
81132225ebb4SBram Moolenaar 	, char_u *lang
81142225ebb4SBram Moolenaar #endif
81152225ebb4SBram Moolenaar 	)
81162225ebb4SBram Moolenaar {
81172225ebb4SBram Moolenaar     int		fcount;
81182225ebb4SBram Moolenaar     char_u	**fnames;
81192225ebb4SBram Moolenaar     int		fi;
81202225ebb4SBram Moolenaar 
812100bf8cd2SBram Moolenaar     // Find all "*.txt" and "*.??x" files in the "doc" directory.
81222225ebb4SBram Moolenaar     add_pathsep(dirname);
81232225ebb4SBram Moolenaar     STRCAT(dirname, "doc/*.\\(txt\\|??x\\)");
81242225ebb4SBram Moolenaar     if (gen_expand_wildcards(1, &dirname, &fcount,
81252225ebb4SBram Moolenaar 		&fnames, EW_FILE|EW_SILENT) == OK
81262225ebb4SBram Moolenaar 	    && fcount > 0)
81272225ebb4SBram Moolenaar     {
81282225ebb4SBram Moolenaar 	for (fi = 0; fi < fcount && !got_int; ++fi)
81292225ebb4SBram Moolenaar 	{
81302225ebb4SBram Moolenaar #ifdef FEAT_MULTI_LANG
813100bf8cd2SBram Moolenaar 	    // Skip files for a different language.
81322225ebb4SBram Moolenaar 	    if (lang != NULL
81332225ebb4SBram Moolenaar 		    && STRNICMP(lang, fnames[fi]
81342225ebb4SBram Moolenaar 				    + STRLEN(fnames[fi]) - 3, 2) != 0
81352225ebb4SBram Moolenaar 		    && !(STRNICMP(lang, "en", 2) == 0
81362225ebb4SBram Moolenaar 			&& STRNICMP("txt", fnames[fi]
81372225ebb4SBram Moolenaar 			    + STRLEN(fnames[fi]) - 3, 3) == 0))
81382225ebb4SBram Moolenaar 		continue;
81392225ebb4SBram Moolenaar #endif
81402225ebb4SBram Moolenaar 
81419afe5e9cSBram Moolenaar 	    hgr_search_file(qfl, fnames[fi], p_vc, p_regmatch);
8142071d4279SBram Moolenaar 	}
8143071d4279SBram Moolenaar 	FreeWild(fcount, fnames);
8144071d4279SBram Moolenaar     }
8145071d4279SBram Moolenaar }
814610b7b39bSBram Moolenaar 
81472225ebb4SBram Moolenaar /*
814818cebf44SBram Moolenaar  * Search for a pattern in all the help files in the 'runtimepath'
814918cebf44SBram Moolenaar  * and add the matches to a quickfix list.
8150c631f2dfSBram Moolenaar  * 'lang' is the language specifier.  If supplied, then only matches in the
815118cebf44SBram Moolenaar  * specified language are found.
81522225ebb4SBram Moolenaar  */
81532225ebb4SBram Moolenaar     static void
hgr_search_in_rtp(qf_list_T * qfl,regmatch_T * p_regmatch,char_u * lang)81549afe5e9cSBram Moolenaar hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch, char_u *lang)
81552225ebb4SBram Moolenaar {
81562225ebb4SBram Moolenaar     char_u	*p;
81572225ebb4SBram Moolenaar 
81582225ebb4SBram Moolenaar     vimconv_T	vc;
81592225ebb4SBram Moolenaar 
816000bf8cd2SBram Moolenaar     // Help files are in utf-8 or latin1, convert lines when 'encoding'
816100bf8cd2SBram Moolenaar     // differs.
81622225ebb4SBram Moolenaar     vc.vc_type = CONV_NONE;
81632225ebb4SBram Moolenaar     if (!enc_utf8)
81642225ebb4SBram Moolenaar 	convert_setup(&vc, (char_u *)"utf-8", p_enc);
81652225ebb4SBram Moolenaar 
816600bf8cd2SBram Moolenaar     // Go through all the directories in 'runtimepath'
81672225ebb4SBram Moolenaar     p = p_rtp;
81682225ebb4SBram Moolenaar     while (*p != NUL && !got_int)
81692225ebb4SBram Moolenaar     {
81702225ebb4SBram Moolenaar 	copy_option_part(&p, NameBuff, MAXPATHL, ",");
81712225ebb4SBram Moolenaar 
81729afe5e9cSBram Moolenaar 	hgr_search_files_in_dir(qfl, NameBuff, p_regmatch, &vc
81732225ebb4SBram Moolenaar #ifdef FEAT_MULTI_LANG
81742225ebb4SBram Moolenaar 		, lang
81752225ebb4SBram Moolenaar #endif
81762225ebb4SBram Moolenaar 		);
81772225ebb4SBram Moolenaar     }
81782225ebb4SBram Moolenaar 
817910b7b39bSBram Moolenaar     if (vc.vc_type != CONV_NONE)
818010b7b39bSBram Moolenaar 	convert_setup(&vc, NULL, NULL);
81812225ebb4SBram Moolenaar }
81822225ebb4SBram Moolenaar 
81832225ebb4SBram Moolenaar /*
81842225ebb4SBram Moolenaar  * ":helpgrep {pattern}"
81852225ebb4SBram Moolenaar  */
81862225ebb4SBram Moolenaar     void
ex_helpgrep(exarg_T * eap)81872225ebb4SBram Moolenaar ex_helpgrep(exarg_T *eap)
81882225ebb4SBram Moolenaar {
81892225ebb4SBram Moolenaar     regmatch_T	regmatch;
81902225ebb4SBram Moolenaar     char_u	*save_cpo;
81912225ebb4SBram Moolenaar     qf_info_T	*qi = &ql_info;
81922225ebb4SBram Moolenaar     int		new_qi = FALSE;
81932225ebb4SBram Moolenaar     char_u	*au_name =  NULL;
8194c631f2dfSBram Moolenaar     char_u	*lang = NULL;
8195e5a2dc87SBram Moolenaar     int		updated = FALSE;
81962225ebb4SBram Moolenaar 
81972225ebb4SBram Moolenaar     switch (eap->cmdidx)
81982225ebb4SBram Moolenaar     {
81992225ebb4SBram Moolenaar 	case CMD_helpgrep:  au_name = (char_u *)"helpgrep"; break;
82002225ebb4SBram Moolenaar 	case CMD_lhelpgrep: au_name = (char_u *)"lhelpgrep"; break;
82012225ebb4SBram Moolenaar 	default: break;
82022225ebb4SBram Moolenaar     }
82032225ebb4SBram Moolenaar     if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
82042225ebb4SBram Moolenaar 					       curbuf->b_fname, TRUE, curbuf))
82052225ebb4SBram Moolenaar     {
82062225ebb4SBram Moolenaar #ifdef FEAT_EVAL
82072225ebb4SBram Moolenaar 	if (aborting())
82082225ebb4SBram Moolenaar 	    return;
82092225ebb4SBram Moolenaar #endif
82102225ebb4SBram Moolenaar     }
82112225ebb4SBram Moolenaar 
821239665959SBram Moolenaar     if (is_loclist_cmd(eap->cmdidx))
82132225ebb4SBram Moolenaar     {
82142225ebb4SBram Moolenaar 	qi = hgr_get_ll(&new_qi);
82152225ebb4SBram Moolenaar 	if (qi == NULL)
82162225ebb4SBram Moolenaar 	    return;
82172225ebb4SBram Moolenaar     }
82182225ebb4SBram Moolenaar 
8219a16123a6SBram Moolenaar     // Make 'cpoptions' empty, the 'l' flag should not be used here.
8220a16123a6SBram Moolenaar     save_cpo = p_cpo;
8221a16123a6SBram Moolenaar     p_cpo = empty_option;
8222a16123a6SBram Moolenaar 
82239f84ded3SBram Moolenaar     incr_quickfix_busy();
82249f84ded3SBram Moolenaar 
8225c631f2dfSBram Moolenaar #ifdef FEAT_MULTI_LANG
8226c631f2dfSBram Moolenaar     // Check for a specified language
8227c631f2dfSBram Moolenaar     lang = check_help_lang(eap->arg);
8228c631f2dfSBram Moolenaar #endif
82292225ebb4SBram Moolenaar     regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING);
82302225ebb4SBram Moolenaar     regmatch.rm_ic = FALSE;
82312225ebb4SBram Moolenaar     if (regmatch.regprog != NULL)
82322225ebb4SBram Moolenaar     {
8233108e7b42SBram Moolenaar 	qf_list_T	*qfl;
8234108e7b42SBram Moolenaar 
8235c631f2dfSBram Moolenaar 	// create a new quickfix list
82368b62e310SBram Moolenaar 	qf_new_list(qi, qf_cmdtitle(*eap->cmdlinep));
82379afe5e9cSBram Moolenaar 	qfl = qf_get_curlist(qi);
82382225ebb4SBram Moolenaar 
82399afe5e9cSBram Moolenaar 	hgr_search_in_rtp(qfl, &regmatch, lang);
82402225ebb4SBram Moolenaar 
82412225ebb4SBram Moolenaar 	vim_regfree(regmatch.regprog);
8242071d4279SBram Moolenaar 
8243108e7b42SBram Moolenaar 	qfl->qf_nonevalid = FALSE;
8244108e7b42SBram Moolenaar 	qfl->qf_ptr = qfl->qf_start;
8245108e7b42SBram Moolenaar 	qfl->qf_index = 1;
8246108e7b42SBram Moolenaar 	qf_list_changed(qfl);
8247e5a2dc87SBram Moolenaar 	updated = TRUE;
8248071d4279SBram Moolenaar     }
8249071d4279SBram Moolenaar 
82509c24ccc7SBram Moolenaar     if (p_cpo == empty_option)
8251071d4279SBram Moolenaar 	p_cpo = save_cpo;
82529c24ccc7SBram Moolenaar     else
8253e5a2dc87SBram Moolenaar     {
8254e5a2dc87SBram Moolenaar 	// Darn, some plugin changed the value.  If it's still empty it was
8255e5a2dc87SBram Moolenaar 	// changed and restored, need to restore in the complicated way.
8256e5a2dc87SBram Moolenaar 	if (*p_cpo == NUL)
8257e5a2dc87SBram Moolenaar 	    set_option_value((char_u *)"cpo", 0L, save_cpo, 0);
82589c24ccc7SBram Moolenaar 	free_string_option(save_cpo);
8259e5a2dc87SBram Moolenaar     }
8260e5a2dc87SBram Moolenaar 
8261e5a2dc87SBram Moolenaar     if (updated)
8262e5a2dc87SBram Moolenaar 	// This may open a window and source scripts, do this after 'cpo' was
8263e5a2dc87SBram Moolenaar 	// restored.
8264e5a2dc87SBram Moolenaar 	qf_update_buffer(qi, NULL);
8265071d4279SBram Moolenaar 
826673633f84SBram Moolenaar     if (au_name != NULL)
826773633f84SBram Moolenaar     {
826873633f84SBram Moolenaar 	apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
826973633f84SBram Moolenaar 					       curbuf->b_fname, TRUE, curbuf);
8270ec98e93aSBram Moolenaar 	// When adding a location list to an existing location list stack,
8271ec98e93aSBram Moolenaar 	// if the autocmd made the stack invalid, then just return.
8272ec98e93aSBram Moolenaar 	if (!new_qi && IS_LL_STACK(qi) && qf_find_win_with_loclist(qi) == NULL)
82739f84ded3SBram Moolenaar 	{
82749f84ded3SBram Moolenaar 	    decr_quickfix_busy();
827573633f84SBram Moolenaar 	    return;
827673633f84SBram Moolenaar 	}
82779f84ded3SBram Moolenaar     }
827873633f84SBram Moolenaar 
827900bf8cd2SBram Moolenaar     // Jump to first match.
82800398e00aSBram Moolenaar     if (!qf_list_empty(qf_get_curlist(qi)))
82818b6144bdSBram Moolenaar 	qf_jump(qi, 0, 0, FALSE);
828269a7cb47SBram Moolenaar     else
8283f9e3e09fSBram Moolenaar 	semsg(_(e_nomatch2), eap->arg);
82848b6144bdSBram Moolenaar 
82859f84ded3SBram Moolenaar     decr_quickfix_busy();
82869f84ded3SBram Moolenaar 
82878b6144bdSBram Moolenaar     if (eap->cmdidx == CMD_lhelpgrep)
82888b6144bdSBram Moolenaar     {
8289c631f2dfSBram Moolenaar 	// If the help window is not opened or if it already points to the
8290c631f2dfSBram Moolenaar 	// correct location list, then free the new location list.
8291d28cc3f5SBram Moolenaar 	if (!bt_help(curwin->w_buffer) || curwin->w_llist == qi)
82928b6144bdSBram Moolenaar 	{
82938b6144bdSBram Moolenaar 	    if (new_qi)
82948b6144bdSBram Moolenaar 		ll_free_all(&qi);
82958b6144bdSBram Moolenaar 	}
82968b6144bdSBram Moolenaar 	else if (curwin->w_llist == NULL)
82978b6144bdSBram Moolenaar 	    curwin->w_llist = qi;
82988b6144bdSBram Moolenaar     }
8299071d4279SBram Moolenaar }
830063d9e730SBram Moolenaar #endif // FEAT_QUICKFIX
8301e677df8dSBram Moolenaar 
8302e677df8dSBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
8303e677df8dSBram Moolenaar # ifdef FEAT_QUICKFIX
8304e677df8dSBram Moolenaar     static void
get_qf_loc_list(int is_qf,win_T * wp,typval_T * what_arg,typval_T * rettv)8305e677df8dSBram Moolenaar get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
8306e677df8dSBram Moolenaar {
8307e677df8dSBram Moolenaar     if (what_arg->v_type == VAR_UNKNOWN)
8308e677df8dSBram Moolenaar     {
8309e677df8dSBram Moolenaar 	if (rettv_list_alloc(rettv) == OK)
8310e677df8dSBram Moolenaar 	    if (is_qf || wp != NULL)
8311858ba06dSBram Moolenaar 		(void)get_errorlist(NULL, wp, -1, 0, rettv->vval.v_list);
8312e677df8dSBram Moolenaar     }
8313e677df8dSBram Moolenaar     else
8314e677df8dSBram Moolenaar     {
8315e677df8dSBram Moolenaar 	if (rettv_dict_alloc(rettv) == OK)
8316e677df8dSBram Moolenaar 	    if (is_qf || (wp != NULL))
8317e677df8dSBram Moolenaar 	    {
8318e677df8dSBram Moolenaar 		if (what_arg->v_type == VAR_DICT)
8319e677df8dSBram Moolenaar 		{
8320e677df8dSBram Moolenaar 		    dict_T	*d = what_arg->vval.v_dict;
8321e677df8dSBram Moolenaar 
8322e677df8dSBram Moolenaar 		    if (d != NULL)
8323e677df8dSBram Moolenaar 			qf_get_properties(wp, d, rettv->vval.v_dict);
8324e677df8dSBram Moolenaar 		}
8325e677df8dSBram Moolenaar 		else
8326e677df8dSBram Moolenaar 		    emsg(_(e_dictreq));
8327e677df8dSBram Moolenaar 	    }
8328e677df8dSBram Moolenaar     }
8329e677df8dSBram Moolenaar }
8330e677df8dSBram Moolenaar # endif
8331e677df8dSBram Moolenaar 
8332e677df8dSBram Moolenaar /*
8333e677df8dSBram Moolenaar  * "getloclist()" function
8334e677df8dSBram Moolenaar  */
8335e677df8dSBram Moolenaar     void
f_getloclist(typval_T * argvars UNUSED,typval_T * rettv UNUSED)8336e677df8dSBram Moolenaar f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8337e677df8dSBram Moolenaar {
8338e677df8dSBram Moolenaar # ifdef FEAT_QUICKFIX
8339e677df8dSBram Moolenaar     win_T	*wp;
8340e677df8dSBram Moolenaar 
83414490ec4eSYegappan Lakshmanan     if (in_vim9script()
83424490ec4eSYegappan Lakshmanan 	    && (check_for_number_arg(argvars, 0) == FAIL
83434490ec4eSYegappan Lakshmanan 		|| check_for_opt_dict_arg(argvars, 1) == FAIL))
83444490ec4eSYegappan Lakshmanan 	return;
83454490ec4eSYegappan Lakshmanan 
8346e677df8dSBram Moolenaar     wp = find_win_by_nr_or_id(&argvars[0]);
8347e677df8dSBram Moolenaar     get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
8348e677df8dSBram Moolenaar # endif
8349e677df8dSBram Moolenaar }
8350e677df8dSBram Moolenaar 
8351e677df8dSBram Moolenaar /*
8352e677df8dSBram Moolenaar  * "getqflist()" function
8353e677df8dSBram Moolenaar  */
8354e677df8dSBram Moolenaar     void
f_getqflist(typval_T * argvars UNUSED,typval_T * rettv UNUSED)8355e677df8dSBram Moolenaar f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8356e677df8dSBram Moolenaar {
8357e677df8dSBram Moolenaar # ifdef FEAT_QUICKFIX
83584490ec4eSYegappan Lakshmanan     if (in_vim9script() && check_for_opt_dict_arg(argvars, 0) == FAIL)
83594490ec4eSYegappan Lakshmanan 	return;
83604490ec4eSYegappan Lakshmanan 
8361e677df8dSBram Moolenaar     get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
8362e677df8dSBram Moolenaar # endif
8363e677df8dSBram Moolenaar }
8364e677df8dSBram Moolenaar 
8365e677df8dSBram Moolenaar /*
8366e677df8dSBram Moolenaar  * Used by "setqflist()" and "setloclist()" functions
8367e677df8dSBram Moolenaar  */
8368e677df8dSBram Moolenaar     static void
set_qf_ll_list(win_T * wp UNUSED,typval_T * list_arg UNUSED,typval_T * action_arg UNUSED,typval_T * what_arg UNUSED,typval_T * rettv)8369e677df8dSBram Moolenaar set_qf_ll_list(
8370e677df8dSBram Moolenaar     win_T	*wp UNUSED,
8371e677df8dSBram Moolenaar     typval_T	*list_arg UNUSED,
8372e677df8dSBram Moolenaar     typval_T	*action_arg UNUSED,
8373e677df8dSBram Moolenaar     typval_T	*what_arg UNUSED,
8374e677df8dSBram Moolenaar     typval_T	*rettv)
8375e677df8dSBram Moolenaar {
8376e677df8dSBram Moolenaar # ifdef FEAT_QUICKFIX
8377e677df8dSBram Moolenaar     static char *e_invact = N_("E927: Invalid action: '%s'");
8378e677df8dSBram Moolenaar     char_u	*act;
8379e677df8dSBram Moolenaar     int		action = 0;
8380e677df8dSBram Moolenaar     static int	recursive = 0;
8381e677df8dSBram Moolenaar # endif
8382e677df8dSBram Moolenaar 
8383e677df8dSBram Moolenaar     rettv->vval.v_number = -1;
8384e677df8dSBram Moolenaar 
8385e677df8dSBram Moolenaar # ifdef FEAT_QUICKFIX
8386e677df8dSBram Moolenaar     if (list_arg->v_type != VAR_LIST)
8387e677df8dSBram Moolenaar 	emsg(_(e_listreq));
8388e677df8dSBram Moolenaar     else if (recursive != 0)
8389e677df8dSBram Moolenaar 	emsg(_(e_au_recursive));
8390e677df8dSBram Moolenaar     else
8391e677df8dSBram Moolenaar     {
8392e677df8dSBram Moolenaar 	list_T  *l = list_arg->vval.v_list;
839390049492SBram Moolenaar 	dict_T	*what = NULL;
8394e677df8dSBram Moolenaar 	int	valid_dict = TRUE;
8395e677df8dSBram Moolenaar 
8396e677df8dSBram Moolenaar 	if (action_arg->v_type == VAR_STRING)
8397e677df8dSBram Moolenaar 	{
8398e677df8dSBram Moolenaar 	    act = tv_get_string_chk(action_arg);
8399e677df8dSBram Moolenaar 	    if (act == NULL)
8400e677df8dSBram Moolenaar 		return;		// type error; errmsg already given
8401e677df8dSBram Moolenaar 	    if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
8402e677df8dSBram Moolenaar 		    act[1] == NUL)
8403e677df8dSBram Moolenaar 		action = *act;
8404e677df8dSBram Moolenaar 	    else
8405e677df8dSBram Moolenaar 		semsg(_(e_invact), act);
8406e677df8dSBram Moolenaar 	}
8407e677df8dSBram Moolenaar 	else if (action_arg->v_type == VAR_UNKNOWN)
8408e677df8dSBram Moolenaar 	    action = ' ';
8409e677df8dSBram Moolenaar 	else
8410e677df8dSBram Moolenaar 	    emsg(_(e_stringreq));
8411e677df8dSBram Moolenaar 
8412e677df8dSBram Moolenaar 	if (action_arg->v_type != VAR_UNKNOWN
8413e677df8dSBram Moolenaar 		&& what_arg->v_type != VAR_UNKNOWN)
8414e677df8dSBram Moolenaar 	{
841590049492SBram Moolenaar 	    if (what_arg->v_type == VAR_DICT && what_arg->vval.v_dict != NULL)
841690049492SBram Moolenaar 		what = what_arg->vval.v_dict;
8417e677df8dSBram Moolenaar 	    else
8418e677df8dSBram Moolenaar 	    {
8419e677df8dSBram Moolenaar 		emsg(_(e_dictreq));
8420e677df8dSBram Moolenaar 		valid_dict = FALSE;
8421e677df8dSBram Moolenaar 	    }
8422e677df8dSBram Moolenaar 	}
8423e677df8dSBram Moolenaar 
8424e677df8dSBram Moolenaar 	++recursive;
842590049492SBram Moolenaar 	if (l != NULL && action && valid_dict
842690049492SBram Moolenaar 		    && set_errorlist(wp, l, action,
8427e677df8dSBram Moolenaar 		     (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
842890049492SBram Moolenaar 		     what) == OK)
8429e677df8dSBram Moolenaar 	    rettv->vval.v_number = 0;
8430e677df8dSBram Moolenaar 	--recursive;
8431e677df8dSBram Moolenaar     }
8432e677df8dSBram Moolenaar # endif
8433e677df8dSBram Moolenaar }
8434e677df8dSBram Moolenaar 
8435e677df8dSBram Moolenaar /*
8436e677df8dSBram Moolenaar  * "setloclist()" function
8437e677df8dSBram Moolenaar  */
8438e677df8dSBram Moolenaar     void
f_setloclist(typval_T * argvars,typval_T * rettv)8439e677df8dSBram Moolenaar f_setloclist(typval_T *argvars, typval_T *rettv)
8440e677df8dSBram Moolenaar {
8441e677df8dSBram Moolenaar     win_T	*win;
8442e677df8dSBram Moolenaar 
8443e677df8dSBram Moolenaar     rettv->vval.v_number = -1;
8444e677df8dSBram Moolenaar 
844583494b4aSYegappan Lakshmanan     if (in_vim9script()
844683494b4aSYegappan Lakshmanan 	    && (check_for_number_arg(argvars, 0) == FAIL
844783494b4aSYegappan Lakshmanan 		|| check_for_list_arg(argvars, 1) == FAIL
844883494b4aSYegappan Lakshmanan 		|| check_for_opt_string_arg(argvars, 2) == FAIL
844983494b4aSYegappan Lakshmanan 		|| (argvars[2].v_type != VAR_UNKNOWN
845083494b4aSYegappan Lakshmanan 		    && check_for_opt_dict_arg(argvars, 3) == FAIL)))
845183494b4aSYegappan Lakshmanan 	return;
845283494b4aSYegappan Lakshmanan 
8453e677df8dSBram Moolenaar     win = find_win_by_nr_or_id(&argvars[0]);
8454e677df8dSBram Moolenaar     if (win != NULL)
8455e677df8dSBram Moolenaar 	set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
8456e677df8dSBram Moolenaar }
8457e677df8dSBram Moolenaar 
8458e677df8dSBram Moolenaar /*
8459e677df8dSBram Moolenaar  * "setqflist()" function
8460e677df8dSBram Moolenaar  */
8461e677df8dSBram Moolenaar     void
f_setqflist(typval_T * argvars,typval_T * rettv)8462e677df8dSBram Moolenaar f_setqflist(typval_T *argvars, typval_T *rettv)
8463e677df8dSBram Moolenaar {
846483494b4aSYegappan Lakshmanan     if (in_vim9script()
846583494b4aSYegappan Lakshmanan 	    && (check_for_list_arg(argvars, 0) == FAIL
846683494b4aSYegappan Lakshmanan 		|| check_for_opt_string_arg(argvars, 1) == FAIL
846783494b4aSYegappan Lakshmanan 		|| (argvars[1].v_type != VAR_UNKNOWN
846883494b4aSYegappan Lakshmanan 		    && check_for_opt_dict_arg(argvars, 2) == FAIL)))
846983494b4aSYegappan Lakshmanan 	return;
847083494b4aSYegappan Lakshmanan 
8471e677df8dSBram Moolenaar     set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
8472e677df8dSBram Moolenaar }
8473e677df8dSBram Moolenaar #endif
8474