blob: dbde1550f2eaec4e9a67a134153cd82d07cd0a63 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * quickfix.c: functions for quickfix mode, using a file with error messages
12 */
13
14#include "vim.h"
15
16#if defined(FEAT_QUICKFIX) || defined(PROTO)
17
18struct dir_stack_T
19{
20 struct dir_stack_T *next;
21 char_u *dirname;
22};
23
24static struct dir_stack_T *dir_stack = NULL;
25
26/*
27 * for each error the next struct is allocated and linked in a list
28 */
29struct qf_line
30{
31 struct qf_line *qf_next; /* pointer to next error in the list */
32 struct qf_line *qf_prev; /* pointer to previous error in the list */
33 linenr_T qf_lnum; /* line number where the error occurred */
34 int qf_fnum; /* file number for the line */
35 int qf_col; /* column where the error occurred */
36 int qf_nr; /* error number */
37 char_u *qf_text; /* description of the error */
38 char_u qf_virt_col; /* set to TRUE if qf_col is screen column */
39 char_u qf_cleared;/* set to TRUE if line has been deleted */
40 char_u qf_type; /* type of the error (mostly 'E'); 1 for
41 :helpgrep */
42 char_u qf_valid; /* valid error message detected */
43};
44
45/*
46 * There is a stack of error lists.
47 */
48#define LISTCOUNT 10
49
50struct qf_list
51{
52 struct qf_line *qf_start; /* pointer to the first error */
53 struct qf_line *qf_ptr; /* pointer to the current error */
54 int qf_count; /* number of errors (0 means no error list) */
55 int qf_index; /* current index in the error list */
56 int qf_nonevalid; /* TRUE if not a single valid entry found */
57} qf_lists[LISTCOUNT];
58
59static int qf_curlist = 0; /* current error list */
60static int qf_listcount = 0; /* current number of lists */
61
62#define FMT_PATTERNS 9 /* maximum number of % recognized */
63
64/*
65 * Structure used to hold the info of one part of 'errorformat'
66 */
67struct eformat
68{
69 regprog_T *prog; /* pre-formatted part of 'errorformat' */
70 struct eformat *next; /* pointer to next (NULL if last) */
71 char_u addr[FMT_PATTERNS]; /* indices of used % patterns */
72 char_u prefix; /* prefix of this format line: */
73 /* 'D' enter directory */
74 /* 'X' leave directory */
75 /* 'A' start of multi-line message */
76 /* 'E' error message */
77 /* 'W' warning message */
78 /* 'I' informational message */
79 /* 'C' continuation line */
80 /* 'Z' end of multi-line message */
81 /* 'G' general, unspecific message */
82 /* 'P' push file (partial) message */
83 /* 'Q' pop/quit file (partial) message */
84 /* 'O' overread (partial) message */
85 char_u flags; /* additional flags given in prefix */
86 /* '-' do not include this line */
87};
88
Bram Moolenaar86b68352004-12-27 21:59:20 +000089static int qf_init_ext __ARGS((char_u *efile, buf_T *buf, char_u *errorformat, int newlist, linenr_T lnumfirst, linenr_T lnumlast));
Bram Moolenaar071d4272004-06-13 20:20:40 +000090static void qf_new_list __ARGS((void));
91static int qf_add_entry __ARGS((struct qf_line **prevp, char_u *dir, char_u *fname, char_u *mesg, long lnum, int col, int virt_col, int nr, int type, int valid));
92static void qf_msg __ARGS((void));
93static void qf_free __ARGS((int idx));
94static char_u *qf_types __ARGS((int, int));
95static int qf_get_fnum __ARGS((char_u *, char_u *));
96static char_u *qf_push_dir __ARGS((char_u *, struct dir_stack_T **));
97static char_u *qf_pop_dir __ARGS((struct dir_stack_T **));
98static char_u *qf_guess_filepath __ARGS((char_u *));
99static void qf_fmt_text __ARGS((char_u *text, char_u *buf, int bufsize));
100static void qf_clean_dir_stack __ARGS((struct dir_stack_T **));
101#ifdef FEAT_WINDOWS
102static int qf_win_pos_update __ARGS((int old_qf_index));
103static buf_T *qf_find_buf __ARGS((void));
104static void qf_update_buffer __ARGS((void));
105static void qf_fill_buffer __ARGS((void));
106#endif
107static char_u *get_mef_name __ARGS((void));
108
109/*
Bram Moolenaar86b68352004-12-27 21:59:20 +0000110 * Read the errorfile "efile" into memory, line by line, building the error
111 * list.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000112 * Return -1 for error, number of errors for success.
113 */
114 int
115qf_init(efile, errorformat, newlist)
116 char_u *efile;
117 char_u *errorformat;
118 int newlist; /* TRUE: start a new error list */
119{
Bram Moolenaar86b68352004-12-27 21:59:20 +0000120 if (efile == NULL)
121 return FAIL;
122 return qf_init_ext(efile, curbuf, errorformat, newlist,
123 (linenr_T)0, (linenr_T)0);
124}
125
126/*
127 * Read the errorfile "efile" into memory, line by line, building the error
128 * list.
129 * Alternative: when "efile" is null read errors from buffer "buf".
130 * Always use 'errorformat' from "buf" if there is a local value.
131 * Then lnumfirst and lnumlast specify the range of lines to use.
132 * Return -1 for error, number of errors for success.
133 */
134 static int
135qf_init_ext(efile, buf, errorformat, newlist, lnumfirst, lnumlast)
136 char_u *efile;
137 buf_T *buf;
138 char_u *errorformat;
139 int newlist; /* TRUE: start a new error list */
140 linenr_T lnumfirst; /* first line number to use */
141 linenr_T lnumlast; /* last line number to use */
142{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143 char_u *namebuf;
144 char_u *errmsg;
145 char_u *fmtstr = NULL;
146 int col = 0;
147 char_u use_virt_col = FALSE;
148 int type = 0;
149 int valid;
Bram Moolenaar86b68352004-12-27 21:59:20 +0000150 linenr_T buflnum = lnumfirst;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000151 long lnum = 0L;
152 int enr = 0;
Bram Moolenaar86b68352004-12-27 21:59:20 +0000153 FILE *fd = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000154 struct qf_line *qfprev = NULL; /* init to make SASC shut up */
155 char_u *efmp;
156 struct eformat *fmt_first = NULL;
157 struct eformat *fmt_last = NULL;
158 struct eformat *fmt_ptr;
159 char_u *efm;
160 char_u *ptr;
161 char_u *srcptr;
162 int len;
163 int i;
164 int round;
165 int idx = 0;
166 int multiline = FALSE;
167 int multiignore = FALSE;
168 int multiscan = FALSE;
169 int retval = -1; /* default: return error flag */
170 char_u *directory = NULL;
171 char_u *currfile = NULL;
172 char_u *tail = NULL;
173 struct dir_stack_T *file_stack = NULL;
174 regmatch_T regmatch;
175 static struct fmtpattern
176 {
177 char_u convchar;
178 char *pattern;
179 } fmt_pat[FMT_PATTERNS] =
180 {
181 {'f', "\\f\\+"},
182 {'n', "\\d\\+"},
183 {'l', "\\d\\+"},
184 {'c', "\\d\\+"},
185 {'t', "."},
186 {'m', ".\\+"},
187 {'r', ".*"},
188 {'p', "[- .]*"},
189 {'v', "\\d\\+"}
190 };
191
Bram Moolenaar071d4272004-06-13 20:20:40 +0000192 namebuf = alloc(CMDBUFFSIZE + 1);
193 errmsg = alloc(CMDBUFFSIZE + 1);
194 if (namebuf == NULL || errmsg == NULL)
195 goto qf_init_end;
196
Bram Moolenaar86b68352004-12-27 21:59:20 +0000197 if (efile != NULL && (fd = mch_fopen((char *)efile, "r")) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198 {
199 EMSG2(_(e_openerrf), efile);
200 goto qf_init_end;
201 }
202
203 if (newlist || qf_curlist == qf_listcount)
204 /* make place for a new list */
205 qf_new_list();
206 else if (qf_lists[qf_curlist].qf_count > 0)
207 /* Adding to existing list, find last entry. */
208 for (qfprev = qf_lists[qf_curlist].qf_start;
209 qfprev->qf_next != qfprev; qfprev = qfprev->qf_next)
210 ;
211
212/*
213 * Each part of the format string is copied and modified from errorformat to
214 * regex prog. Only a few % characters are allowed.
215 */
216 /* Use the local value of 'errorformat' if it's set. */
Bram Moolenaar86b68352004-12-27 21:59:20 +0000217 if (errorformat == p_efm && *buf->b_p_efm != NUL)
218 efm = buf->b_p_efm;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000219 else
220 efm = errorformat;
221 /*
222 * Get some space to modify the format string into.
223 */
224 i = (FMT_PATTERNS * 3) + ((int)STRLEN(efm) << 2);
225 for (round = FMT_PATTERNS; round > 0; )
226 i += (int)STRLEN(fmt_pat[--round].pattern);
227#ifdef COLON_IN_FILENAME
228 i += 12; /* "%f" can become twelve chars longer */
229#else
230 i += 2; /* "%f" can become two chars longer */
231#endif
232 if ((fmtstr = alloc(i)) == NULL)
233 goto error2;
234
235 while (efm[0])
236 {
237 /*
238 * Allocate a new eformat structure and put it at the end of the list
239 */
240 fmt_ptr = (struct eformat *)alloc((unsigned)sizeof(struct eformat));
241 if (fmt_ptr == NULL)
242 goto error2;
243 if (fmt_first == NULL) /* first one */
244 fmt_first = fmt_ptr;
245 else
246 fmt_last->next = fmt_ptr;
247 fmt_last = fmt_ptr;
248 fmt_ptr->prefix = NUL;
249 fmt_ptr->flags = NUL;
250 fmt_ptr->next = NULL;
251 fmt_ptr->prog = NULL;
252 for (round = FMT_PATTERNS; round > 0; )
253 fmt_ptr->addr[--round] = NUL;
254 /* round is 0 now */
255
256 /*
257 * Isolate one part in the 'errorformat' option
258 */
259 for (len = 0; efm[len] != NUL && efm[len] != ','; ++len)
260 if (efm[len] == '\\' && efm[len + 1] != NUL)
261 ++len;
262
263 /*
264 * Build regexp pattern from current 'errorformat' option
265 */
266 ptr = fmtstr;
267 *ptr++ = '^';
268 for (efmp = efm; efmp < efm + len; ++efmp)
269 {
270 if (*efmp == '%')
271 {
272 ++efmp;
273 for (idx = 0; idx < FMT_PATTERNS; ++idx)
274 if (fmt_pat[idx].convchar == *efmp)
275 break;
276 if (idx < FMT_PATTERNS)
277 {
278 if (fmt_ptr->addr[idx])
279 {
280 sprintf((char *)errmsg,
281 _("E372: Too many %%%c in format string"), *efmp);
282 EMSG(errmsg);
283 goto error2;
284 }
285 if ((idx
286 && idx < 6
287 && vim_strchr((char_u *)"DXOPQ",
288 fmt_ptr->prefix) != NULL)
289 || (idx == 6
290 && vim_strchr((char_u *)"OPQ",
291 fmt_ptr->prefix) == NULL))
292 {
293 sprintf((char *)errmsg,
294 _("E373: Unexpected %%%c in format string"), *efmp);
295 EMSG(errmsg);
296 goto error2;
297 }
298 fmt_ptr->addr[idx] = (char_u)++round;
299 *ptr++ = '\\';
300 *ptr++ = '(';
301#ifdef BACKSLASH_IN_FILENAME
302 if (*efmp == 'f')
303 {
304 /* Also match "c:" in the file name, even when
305 * checking for a colon next: "%f:".
306 * "\%(\a:\)\=" */
307 STRCPY(ptr, "\\%(\\a:\\)\\=");
308 ptr += 10;
309 }
310#endif
311 if (*efmp == 'f' && efmp[1] != NUL
312 && efmp[1] != '\\' && efmp[1] != '%')
313 {
314 /* A file name may contain spaces, but this isn't in
315 * "\f". use "[^x]\+" instead (x is next character) */
316 *ptr++ = '[';
317 *ptr++ = '^';
318 *ptr++ = efmp[1];
319 *ptr++ = ']';
320 *ptr++ = '\\';
321 *ptr++ = '+';
322 }
323 else
324 {
325 srcptr = (char_u *)fmt_pat[idx].pattern;
326 while ((*ptr = *srcptr++) != NUL)
327 ++ptr;
328 }
329 *ptr++ = '\\';
330 *ptr++ = ')';
331 }
332 else if (*efmp == '*')
333 {
334 if (*++efmp == '[' || *efmp == '\\')
335 {
336 if ((*ptr++ = *efmp) == '[') /* %*[^a-z0-9] etc. */
337 {
338 if (efmp[1] == '^')
339 *ptr++ = *++efmp;
340 if (efmp < efm + len)
341 {
342 *ptr++ = *++efmp; /* could be ']' */
343 while (efmp < efm + len
344 && (*ptr++ = *++efmp) != ']')
345 /* skip */;
346 if (efmp == efm + len)
347 {
348 EMSG(_("E374: Missing ] in format string"));
349 goto error2;
350 }
351 }
352 }
353 else if (efmp < efm + len) /* %*\D, %*\s etc. */
354 *ptr++ = *++efmp;
355 *ptr++ = '\\';
356 *ptr++ = '+';
357 }
358 else
359 {
360 /* TODO: scanf()-like: %*ud, %*3c, %*f, ... ? */
361 sprintf((char *)errmsg,
362 _("E375: Unsupported %%%c in format string"), *efmp);
363 EMSG(errmsg);
364 goto error2;
365 }
366 }
367 else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL)
368 *ptr++ = *efmp; /* regexp magic characters */
369 else if (*efmp == '#')
370 *ptr++ = '*';
371 else if (efmp == efm + 1) /* analyse prefix */
372 {
373 if (vim_strchr((char_u *)"+-", *efmp) != NULL)
374 fmt_ptr->flags = *efmp++;
375 if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL)
376 fmt_ptr->prefix = *efmp;
377 else
378 {
379 sprintf((char *)errmsg,
380 _("E376: Invalid %%%c in format string prefix"), *efmp);
381 EMSG(errmsg);
382 goto error2;
383 }
384 }
385 else
386 {
387 sprintf((char *)errmsg,
388 _("E377: Invalid %%%c in format string"), *efmp);
389 EMSG(errmsg);
390 goto error2;
391 }
392 }
393 else /* copy normal character */
394 {
395 if (*efmp == '\\' && efmp + 1 < efm + len)
396 ++efmp;
397 else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL)
398 *ptr++ = '\\'; /* escape regexp atoms */
399 if (*efmp)
400 *ptr++ = *efmp;
401 }
402 }
403 *ptr++ = '$';
404 *ptr = NUL;
405 if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL)
406 goto error2;
407 /*
408 * Advance to next part
409 */
410 efm = skip_to_option_part(efm + len); /* skip comma and spaces */
411 }
412 if (fmt_first == NULL) /* nothing found */
413 {
414 EMSG(_("E378: 'errorformat' contains no pattern"));
415 goto error2;
416 }
417
418 /*
419 * got_int is reset here, because it was probably set when killing the
420 * ":make" command, but we still want to read the errorfile then.
421 */
422 got_int = FALSE;
423
424 /* Always ignore case when looking for a matching error. */
425 regmatch.rm_ic = TRUE;
426
427 /*
428 * Read the lines in the error file one by one.
429 * Try to recognize one of the error formats in each line.
430 */
Bram Moolenaar86b68352004-12-27 21:59:20 +0000431 while (!got_int)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 {
Bram Moolenaar86b68352004-12-27 21:59:20 +0000433 /* Get the next line. */
434 if (fd == NULL)
435 {
436 if (buflnum > lnumlast)
437 break;
438 STRNCPY(IObuff, ml_get_buf(buf, buflnum++, FALSE), CMDBUFFSIZE - 2);
439 }
440 else if (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) == NULL)
441 break;
442
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443 IObuff[CMDBUFFSIZE - 2] = NUL; /* for very long lines */
444 if ((efmp = vim_strrchr(IObuff, '\n')) != NULL)
445 *efmp = NUL;
446#ifdef USE_CRNL
447 if ((efmp = vim_strrchr(IObuff, '\r')) != NULL)
448 *efmp = NUL;
449#endif
450
451 /*
452 * Try to match each part of 'errorformat' until we find a complete
453 * match or no match.
454 */
455 valid = TRUE;
456restofline:
457 for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next)
458 {
459 idx = fmt_ptr->prefix;
460 if (multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL)
461 continue;
462 namebuf[0] = NUL;
463 if (!multiscan)
464 errmsg[0] = NUL;
465 lnum = 0;
466 col = 0;
467 use_virt_col = FALSE;
468 enr = -1;
469 type = 0;
470 tail = NULL;
471
472 regmatch.regprog = fmt_ptr->prog;
473 if (vim_regexec(&regmatch, IObuff, (colnr_T)0))
474 {
475 if ((idx == 'C' || idx == 'Z') && !multiline)
476 continue;
477 if (vim_strchr((char_u *)"EWI", idx) != NULL)
478 type = idx;
479 else
480 type = 0;
481 /*
482 * Extract error message data from matched line
483 */
484 if ((i = (int)fmt_ptr->addr[0]) > 0) /* %f */
485 {
486 len = (int)(regmatch.endp[i] - regmatch.startp[i]);
487 STRNCPY(namebuf, regmatch.startp[i], len);
488 namebuf[len] = NUL;
489 if (vim_strchr((char_u *)"OPQ", idx) != NULL
490 && mch_getperm(namebuf) == -1)
491 continue;
492 }
493 if ((i = (int)fmt_ptr->addr[1]) > 0) /* %n */
494 enr = (int)atol((char *)regmatch.startp[i]);
495 if ((i = (int)fmt_ptr->addr[2]) > 0) /* %l */
496 lnum = atol((char *)regmatch.startp[i]);
497 if ((i = (int)fmt_ptr->addr[3]) > 0) /* %c */
498 col = (int)atol((char *)regmatch.startp[i]);
499 if ((i = (int)fmt_ptr->addr[4]) > 0) /* %t */
500 type = *regmatch.startp[i];
501 if (fmt_ptr->flags == '+' && !multiscan) /* %+ */
502 STRCPY(errmsg, IObuff);
503 else if ((i = (int)fmt_ptr->addr[5]) > 0) /* %m */
504 {
505 len = (int)(regmatch.endp[i] - regmatch.startp[i]);
506 STRNCPY(errmsg, regmatch.startp[i], len);
507 errmsg[len] = NUL;
508 }
509 if ((i = (int)fmt_ptr->addr[6]) > 0) /* %r */
510 tail = regmatch.startp[i];
511 if ((i = (int)fmt_ptr->addr[7]) > 0) /* %p */
512 {
513 col = (int)(regmatch.endp[i] - regmatch.startp[i] + 1);
514 if (*((char_u *)regmatch.startp[i]) != TAB)
515 use_virt_col = TRUE;
516 }
517 if ((i = (int)fmt_ptr->addr[8]) > 0) /* %v */
518 {
519 col = (int)atol((char *)regmatch.startp[i]);
520 use_virt_col = TRUE;
521 }
522 break;
523 }
524 }
525 multiscan = FALSE;
526 if (!fmt_ptr || idx == 'D' || idx == 'X')
527 {
528 if (fmt_ptr)
529 {
530 if (idx == 'D') /* enter directory */
531 {
532 if (*namebuf == NUL)
533 {
534 EMSG(_("E379: Missing or empty directory name"));
535 goto error2;
536 }
537 if ((directory = qf_push_dir(namebuf, &dir_stack)) == NULL)
538 goto error2;
539 }
540 else if (idx == 'X') /* leave directory */
541 directory = qf_pop_dir(&dir_stack);
542 }
543 namebuf[0] = NUL; /* no match found, remove file name */
544 lnum = 0; /* don't jump to this line */
545 valid = FALSE;
546 STRCPY(errmsg, IObuff); /* copy whole line to error message */
547 if (!fmt_ptr)
548 multiline = multiignore = FALSE;
549 }
550 else if (fmt_ptr)
551 {
552 if (vim_strchr((char_u *)"AEWI", idx) != NULL)
553 multiline = TRUE; /* start of a multi-line message */
554 else if (vim_strchr((char_u *)"CZ", idx) != NULL)
555 { /* continuation of multi-line msg */
556 if (qfprev == NULL)
557 goto error2;
558 if (*errmsg && !multiignore)
559 {
560 len = (int)STRLEN(qfprev->qf_text);
561 if ((ptr = alloc((unsigned)(len + STRLEN(errmsg) + 2)))
562 == NULL)
563 goto error2;
564 STRCPY(ptr, qfprev->qf_text);
565 vim_free(qfprev->qf_text);
566 qfprev->qf_text = ptr;
567 *(ptr += len) = '\n';
568 STRCPY(++ptr, errmsg);
569 }
570 if (qfprev->qf_nr == -1)
571 qfprev->qf_nr = enr;
572 if (vim_isprintc(type) && !qfprev->qf_type)
573 qfprev->qf_type = type; /* only printable chars allowed */
574 if (!qfprev->qf_lnum)
575 qfprev->qf_lnum = lnum;
576 if (!qfprev->qf_col)
577 qfprev->qf_col = col;
578 qfprev->qf_virt_col = use_virt_col;
579 if (!qfprev->qf_fnum)
580 qfprev->qf_fnum = qf_get_fnum(directory,
581 *namebuf || directory ? namebuf
582 : currfile && valid ? currfile : 0);
583 if (idx == 'Z')
584 multiline = multiignore = FALSE;
585 line_breakcheck();
586 continue;
587 }
588 else if (vim_strchr((char_u *)"OPQ", idx) != NULL)
589 {
590 /* global file names */
591 valid = FALSE;
592 if (*namebuf == NUL || mch_getperm(namebuf) >= 0)
593 {
594 if (*namebuf && idx == 'P')
595 currfile = qf_push_dir(namebuf, &file_stack);
596 else if (idx == 'Q')
597 currfile = qf_pop_dir(&file_stack);
598 *namebuf = NUL;
599 if (tail && *tail)
600 {
601 STRCPY(IObuff, skipwhite(tail));
602 multiscan = TRUE;
603 goto restofline;
604 }
605 }
606 }
607 if (fmt_ptr->flags == '-') /* generally exclude this line */
608 {
609 if (multiline)
610 multiignore = TRUE; /* also exclude continuation lines */
611 continue;
612 }
613 }
614
615 if (qf_add_entry(&qfprev,
616 directory,
617 *namebuf || directory
618 ? namebuf
619 : currfile && valid ? currfile : NULL,
620 errmsg,
621 lnum,
622 col,
623 use_virt_col,
624 enr,
625 type,
626 valid) == FAIL)
627 goto error2;
628 line_breakcheck();
629 }
Bram Moolenaar86b68352004-12-27 21:59:20 +0000630 if (fd == NULL || !ferror(fd))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 {
632 if (qf_lists[qf_curlist].qf_index == 0) /* no valid entry found */
633 {
634 qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start;
635 qf_lists[qf_curlist].qf_index = 1;
636 qf_lists[qf_curlist].qf_nonevalid = TRUE;
637 }
638 else
639 {
640 qf_lists[qf_curlist].qf_nonevalid = FALSE;
641 if (qf_lists[qf_curlist].qf_ptr == NULL)
642 qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start;
643 }
644 retval = qf_lists[qf_curlist].qf_count; /* return number of matches */
645 goto qf_init_ok;
646 }
647 EMSG(_(e_readerrf));
648error2:
649 qf_free(qf_curlist);
650 qf_listcount--;
651 if (qf_curlist > 0)
652 --qf_curlist;
653qf_init_ok:
Bram Moolenaar86b68352004-12-27 21:59:20 +0000654 if (fd != NULL)
655 fclose(fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656 for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first)
657 {
658 fmt_first = fmt_ptr->next;
659 vim_free(fmt_ptr->prog);
660 vim_free(fmt_ptr);
661 }
662 qf_clean_dir_stack(&dir_stack);
663 qf_clean_dir_stack(&file_stack);
664qf_init_end:
665 vim_free(namebuf);
666 vim_free(errmsg);
667 vim_free(fmtstr);
668
669#ifdef FEAT_WINDOWS
670 qf_update_buffer();
671#endif
672
673 return retval;
674}
675
676/*
677 * Prepare for adding a new quickfix list.
678 */
679 static void
680qf_new_list()
681{
682 int i;
683
684 /*
685 * If the current entry is not the last entry, delete entries below
686 * the current entry. This makes it possible to browse in a tree-like
687 * way with ":grep'.
688 */
689 while (qf_listcount > qf_curlist + 1)
690 qf_free(--qf_listcount);
691
692 /*
693 * When the stack is full, remove to oldest entry
694 * Otherwise, add a new entry.
695 */
696 if (qf_listcount == LISTCOUNT)
697 {
698 qf_free(0);
699 for (i = 1; i < LISTCOUNT; ++i)
700 qf_lists[i - 1] = qf_lists[i];
701 qf_curlist = LISTCOUNT - 1;
702 }
703 else
704 qf_curlist = qf_listcount++;
705 qf_lists[qf_curlist].qf_index = 0;
706 qf_lists[qf_curlist].qf_count = 0;
707}
708
709/*
710 * Add an entry to the end of the list of errors.
711 * Returns OK or FAIL.
712 */
713 static int
714qf_add_entry(prevp, dir, fname, mesg, lnum, col, virt_col, nr, type, valid)
715 struct qf_line **prevp; /* pointer to previously added entry or NULL */
716 char_u *dir; /* optional directory name */
717 char_u *fname; /* file name or NULL */
718 char_u *mesg; /* message */
719 long lnum; /* line number */
720 int col; /* column */
721 int virt_col; /* using virtual column */
722 int nr; /* error number */
723 int type; /* type character */
724 int valid; /* valid entry */
725{
726 struct qf_line *qfp;
727
728 if ((qfp = (struct qf_line *)alloc((unsigned)sizeof(struct qf_line)))
729 == NULL)
730 return FAIL;
731 qfp->qf_fnum = qf_get_fnum(dir, fname);
732 if ((qfp->qf_text = vim_strsave(mesg)) == NULL)
733 {
734 vim_free(qfp);
735 return FAIL;
736 }
737 qfp->qf_lnum = lnum;
738 qfp->qf_col = col;
739 qfp->qf_virt_col = virt_col;
740 qfp->qf_nr = nr;
741 if (type != 1 && !vim_isprintc(type)) /* only printable chars allowed */
742 type = 0;
743 qfp->qf_type = type;
744 qfp->qf_valid = valid;
745
746 if (qf_lists[qf_curlist].qf_count == 0) /* first element in the list */
747 {
748 qf_lists[qf_curlist].qf_start = qfp;
749 qfp->qf_prev = qfp; /* first element points to itself */
750 }
751 else
752 {
753 qfp->qf_prev = *prevp;
754 (*prevp)->qf_next = qfp;
755 }
756 qfp->qf_next = qfp; /* last element points to itself */
757 qfp->qf_cleared = FALSE;
758 *prevp = qfp;
759 ++qf_lists[qf_curlist].qf_count;
760 if (qf_lists[qf_curlist].qf_index == 0 && qfp->qf_valid)
761 /* first valid entry */
762 {
763 qf_lists[qf_curlist].qf_index = qf_lists[qf_curlist].qf_count;
764 qf_lists[qf_curlist].qf_ptr = qfp;
765 }
766
767 return OK;
768}
769
770/*
771 * get buffer number for file "dir.name"
772 */
773 static int
774qf_get_fnum(directory, fname)
775 char_u *directory;
776 char_u *fname;
777{
778 if (fname == NULL || *fname == NUL) /* no file name */
779 return 0;
780 {
781#ifdef RISCOS
782 /* Name is reported as `main.c', but file is `c.main' */
783 return ro_buflist_add(fname);
784#else
785 char_u *ptr;
786 int fnum;
787
788# ifdef VMS
789 vms_remove_version(fname);
790# endif
791# ifdef BACKSLASH_IN_FILENAME
792 if (directory != NULL)
793 slash_adjust(directory);
794 slash_adjust(fname);
795# endif
796 if (directory != NULL && !vim_isAbsName(fname)
797 && (ptr = concat_fnames(directory, fname, TRUE)) != NULL)
798 {
799 /*
800 * Here we check if the file really exists.
801 * This should normally be true, but if make works without
802 * "leaving directory"-messages we might have missed a
803 * directory change.
804 */
805 if (mch_getperm(ptr) < 0)
806 {
807 vim_free(ptr);
808 directory = qf_guess_filepath(fname);
809 if (directory)
810 ptr = concat_fnames(directory, fname, TRUE);
811 else
812 ptr = vim_strsave(fname);
813 }
814 /* Use concatenated directory name and file name */
815 fnum = buflist_add(ptr, 0);
816 vim_free(ptr);
817 return fnum;
818 }
819 return buflist_add(fname, 0);
820#endif
821 }
822}
823
824/*
825 * push dirbuf onto the directory stack and return pointer to actual dir or
826 * NULL on error
827 */
828 static char_u *
829qf_push_dir(dirbuf, stackptr)
830 char_u *dirbuf;
831 struct dir_stack_T **stackptr;
832{
833 struct dir_stack_T *ds_new;
834 struct dir_stack_T *ds_ptr;
835
836 /* allocate new stack element and hook it in */
837 ds_new = (struct dir_stack_T *)alloc((unsigned)sizeof(struct dir_stack_T));
838 if (ds_new == NULL)
839 return NULL;
840
841 ds_new->next = *stackptr;
842 *stackptr = ds_new;
843
844 /* store directory on the stack */
845 if (vim_isAbsName(dirbuf)
846 || (*stackptr)->next == NULL
847 || (*stackptr && dir_stack != *stackptr))
848 (*stackptr)->dirname = vim_strsave(dirbuf);
849 else
850 {
851 /* Okay we don't have an absolute path.
852 * dirbuf must be a subdir of one of the directories on the stack.
853 * Let's search...
854 */
855 ds_new = (*stackptr)->next;
856 (*stackptr)->dirname = NULL;
857 while (ds_new)
858 {
859 vim_free((*stackptr)->dirname);
860 (*stackptr)->dirname = concat_fnames(ds_new->dirname, dirbuf,
861 TRUE);
862 if (mch_isdir((*stackptr)->dirname) == TRUE)
863 break;
864
865 ds_new = ds_new->next;
866 }
867
868 /* clean up all dirs we already left */
869 while ((*stackptr)->next != ds_new)
870 {
871 ds_ptr = (*stackptr)->next;
872 (*stackptr)->next = (*stackptr)->next->next;
873 vim_free(ds_ptr->dirname);
874 vim_free(ds_ptr);
875 }
876
877 /* Nothing found -> it must be on top level */
878 if (ds_new == NULL)
879 {
880 vim_free((*stackptr)->dirname);
881 (*stackptr)->dirname = vim_strsave(dirbuf);
882 }
883 }
884
885 if ((*stackptr)->dirname != NULL)
886 return (*stackptr)->dirname;
887 else
888 {
889 ds_ptr = *stackptr;
890 *stackptr = (*stackptr)->next;
891 vim_free(ds_ptr);
892 return NULL;
893 }
894}
895
896
897/*
898 * pop dirbuf from the directory stack and return previous directory or NULL if
899 * stack is empty
900 */
901 static char_u *
902qf_pop_dir(stackptr)
903 struct dir_stack_T **stackptr;
904{
905 struct dir_stack_T *ds_ptr;
906
907 /* TODO: Should we check if dirbuf is the directory on top of the stack?
908 * What to do if it isn't? */
909
910 /* pop top element and free it */
911 if (*stackptr != NULL)
912 {
913 ds_ptr = *stackptr;
914 *stackptr = (*stackptr)->next;
915 vim_free(ds_ptr->dirname);
916 vim_free(ds_ptr);
917 }
918
919 /* return NEW top element as current dir or NULL if stack is empty*/
920 return *stackptr ? (*stackptr)->dirname : NULL;
921}
922
923/*
924 * clean up directory stack
925 */
926 static void
927qf_clean_dir_stack(stackptr)
928 struct dir_stack_T **stackptr;
929{
930 struct dir_stack_T *ds_ptr;
931
932 while ((ds_ptr = *stackptr) != NULL)
933 {
934 *stackptr = (*stackptr)->next;
935 vim_free(ds_ptr->dirname);
936 vim_free(ds_ptr);
937 }
938}
939
940/*
941 * Check in which directory of the directory stack the given file can be
942 * found.
943 * Returns a pointer to the directory name or NULL if not found
944 * Cleans up intermediate directory entries.
945 *
946 * TODO: How to solve the following problem?
947 * If we have the this directory tree:
948 * ./
949 * ./aa
950 * ./aa/bb
951 * ./bb
952 * ./bb/x.c
953 * and make says:
954 * making all in aa
955 * making all in bb
956 * x.c:9: Error
957 * Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb.
958 * qf_guess_filepath will return NULL.
959 */
960 static char_u *
961qf_guess_filepath(filename)
962 char_u *filename;
963{
964 struct dir_stack_T *ds_ptr;
965 struct dir_stack_T *ds_tmp;
966 char_u *fullname;
967
968 /* no dirs on the stack - there's nothing we can do */
969 if (dir_stack == NULL)
970 return NULL;
971
972 ds_ptr = dir_stack->next;
973 fullname = NULL;
974 while (ds_ptr)
975 {
976 vim_free(fullname);
977 fullname = concat_fnames(ds_ptr->dirname, filename, TRUE);
978
979 /* If concat_fnames failed, just go on. The worst thing that can happen
980 * is that we delete the entire stack.
981 */
982 if ((fullname != NULL) && (mch_getperm(fullname) >= 0))
983 break;
984
985 ds_ptr = ds_ptr->next;
986 }
987
988 vim_free(fullname);
989
990 /* clean up all dirs we already left */
991 while (dir_stack->next != ds_ptr)
992 {
993 ds_tmp = dir_stack->next;
994 dir_stack->next = dir_stack->next->next;
995 vim_free(ds_tmp->dirname);
996 vim_free(ds_tmp);
997 }
998
999 return ds_ptr==NULL? NULL: ds_ptr->dirname;
1000
1001}
1002
1003/*
1004 * jump to a quickfix line
1005 * if dir == FORWARD go "errornr" valid entries forward
1006 * if dir == BACKWARD go "errornr" valid entries backward
1007 * if dir == FORWARD_FILE go "errornr" valid entries files backward
1008 * if dir == BACKWARD_FILE go "errornr" valid entries files backward
1009 * else if "errornr" is zero, redisplay the same line
1010 * else go to entry "errornr"
1011 */
1012 void
1013qf_jump(dir, errornr, forceit)
1014 int dir;
1015 int errornr;
1016 int forceit;
1017{
1018 struct qf_line *qf_ptr;
1019 struct qf_line *old_qf_ptr;
1020 int qf_index;
1021 int old_qf_fnum;
1022 int old_qf_index;
1023 int prev_index;
1024 static char_u *e_no_more_items = (char_u *)N_("E553: No more items");
1025 char_u *err = e_no_more_items;
1026 linenr_T i;
1027 buf_T *old_curbuf;
1028 linenr_T old_lnum;
1029 char_u *old_swb = p_swb;
1030 colnr_T screen_col;
1031 colnr_T char_col;
1032 char_u *line;
1033#ifdef FEAT_WINDOWS
1034 int opened_window = FALSE;
1035 win_T *win;
1036 win_T *altwin;
1037#endif
1038 int print_message = TRUE;
1039 int len;
1040#ifdef FEAT_FOLDING
1041 int old_KeyTyped = KeyTyped; /* getting file may reset it */
1042#endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001043 int ok = OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001044
1045 if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0)
1046 {
1047 EMSG(_(e_quickfix));
1048 return;
1049 }
1050
1051 qf_ptr = qf_lists[qf_curlist].qf_ptr;
1052 old_qf_ptr = qf_ptr;
1053 qf_index = qf_lists[qf_curlist].qf_index;
1054 old_qf_index = qf_index;
1055 if (dir == FORWARD || dir == FORWARD_FILE) /* next valid entry */
1056 {
1057 while (errornr--)
1058 {
1059 old_qf_ptr = qf_ptr;
1060 prev_index = qf_index;
1061 old_qf_fnum = qf_ptr->qf_fnum;
1062 do
1063 {
1064 if (qf_index == qf_lists[qf_curlist].qf_count
1065 || qf_ptr->qf_next == NULL)
1066 {
1067 qf_ptr = old_qf_ptr;
1068 qf_index = prev_index;
1069 if (err != NULL)
1070 {
1071 EMSG(_(err));
1072 goto theend;
1073 }
1074 errornr = 0;
1075 break;
1076 }
1077 ++qf_index;
1078 qf_ptr = qf_ptr->qf_next;
1079 } while ((!qf_lists[qf_curlist].qf_nonevalid && !qf_ptr->qf_valid)
1080 || (dir == FORWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum));
1081 err = NULL;
1082 }
1083 }
1084 else if (dir == BACKWARD || dir == BACKWARD_FILE) /* prev. valid entry */
1085 {
1086 while (errornr--)
1087 {
1088 old_qf_ptr = qf_ptr;
1089 prev_index = qf_index;
1090 old_qf_fnum = qf_ptr->qf_fnum;
1091 do
1092 {
1093 if (qf_index == 1 || qf_ptr->qf_prev == NULL)
1094 {
1095 qf_ptr = old_qf_ptr;
1096 qf_index = prev_index;
1097 if (err != NULL)
1098 {
1099 EMSG(_(err));
1100 goto theend;
1101 }
1102 errornr = 0;
1103 break;
1104 }
1105 --qf_index;
1106 qf_ptr = qf_ptr->qf_prev;
1107 } while ((!qf_lists[qf_curlist].qf_nonevalid && !qf_ptr->qf_valid)
1108 || (dir == BACKWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum));
1109 err = NULL;
1110 }
1111 }
1112 else if (errornr != 0) /* go to specified number */
1113 {
1114 while (errornr < qf_index && qf_index > 1 && qf_ptr->qf_prev != NULL)
1115 {
1116 --qf_index;
1117 qf_ptr = qf_ptr->qf_prev;
1118 }
1119 while (errornr > qf_index && qf_index < qf_lists[qf_curlist].qf_count
1120 && qf_ptr->qf_next != NULL)
1121 {
1122 ++qf_index;
1123 qf_ptr = qf_ptr->qf_next;
1124 }
1125 }
1126
1127#ifdef FEAT_WINDOWS
1128 qf_lists[qf_curlist].qf_index = qf_index;
1129 if (qf_win_pos_update(old_qf_index))
1130 /* No need to print the error message if it's visible in the error
1131 * window */
1132 print_message = FALSE;
1133
1134 /*
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001135 * For ":helpgrep" find a help window or open one.
1136 */
1137 if (qf_ptr->qf_type == 1 && !curwin->w_buffer->b_help)
1138 {
1139 win_T *wp;
1140 int n;
1141
1142 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1143 if (wp->w_buffer != NULL && wp->w_buffer->b_help)
1144 break;
1145 if (wp != NULL && wp->w_buffer->b_nwindows > 0)
1146 win_enter(wp, TRUE);
1147 else
1148 {
1149 /*
1150 * Split off help window; put it at far top if no position
1151 * specified, the current window is vertically split and narrow.
1152 */
1153 n = WSP_HELP;
1154# ifdef FEAT_VERTSPLIT
1155 if (cmdmod.split == 0 && curwin->w_width != Columns
1156 && curwin->w_width < 80)
1157 n |= WSP_TOP;
1158# endif
1159 if (win_split(0, n) == FAIL)
1160 goto theend;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00001161 opened_window = TRUE; /* close it when fail */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001162
1163 if (curwin->w_height < p_hh)
1164 win_setheight((int)p_hh);
1165 }
1166
1167 if (!p_im)
1168 restart_edit = 0; /* don't want insert mode in help file */
1169 }
1170
1171 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001172 * If currently in the quickfix window, find another window to show the
1173 * file in.
1174 */
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00001175 if (bt_quickfix(curbuf) && !opened_window)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001176 {
1177 /*
1178 * If there is no file specified, we don't know where to go.
1179 * But do advance, otherwise ":cn" gets stuck.
1180 */
1181 if (qf_ptr->qf_fnum == 0)
1182 goto theend;
1183
1184 /*
1185 * If there is only one window, create a new one above the quickfix
1186 * window.
1187 */
1188 if (firstwin == lastwin)
1189 {
1190 if (win_split(0, WSP_ABOVE) == FAIL)
1191 goto failed; /* not enough room for window */
1192 opened_window = TRUE; /* close it when fail */
1193 p_swb = empty_option; /* don't split again */
1194# ifdef FEAT_SCROLLBIND
1195 curwin->w_p_scb = FALSE;
1196# endif
1197 }
1198 else
1199 {
1200 /*
1201 * Try to find a window that shows the right buffer.
1202 * Default to the window just above the quickfix buffer.
1203 */
1204 win = curwin;
1205 altwin = NULL;
1206 for (;;)
1207 {
1208 if (win->w_buffer->b_fnum == qf_ptr->qf_fnum)
1209 break;
1210 if (win->w_prev == NULL)
1211 win = lastwin; /* wrap around the top */
1212 else
1213 win = win->w_prev; /* go to previous window */
1214
1215 if (bt_quickfix(win->w_buffer))
1216 {
1217 /* Didn't find it, go to the window before the quickfix
1218 * window. */
1219 if (altwin != NULL)
1220 win = altwin;
1221 else if (curwin->w_prev != NULL)
1222 win = curwin->w_prev;
1223 else
1224 win = curwin->w_next;
1225 break;
1226 }
1227
1228 /* Remember a usable window. */
1229 if (altwin == NULL && !win->w_p_pvw
1230 && win->w_buffer->b_p_bt[0] == NUL)
1231 altwin = win;
1232 }
1233
1234 win_goto(win);
1235 }
1236 }
1237#endif
1238
1239 /*
1240 * If there is a file name,
1241 * read the wanted file if needed, and check autowrite etc.
1242 */
1243 old_curbuf = curbuf;
1244 old_lnum = curwin->w_cursor.lnum;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001245
1246 if (qf_ptr->qf_fnum != 0)
1247 {
1248 if (qf_ptr->qf_type == 1)
1249 {
1250 /* Open help file (do_ecmd() will set b_help flag, readfile() will
1251 * set b_p_ro flag). */
1252 if (!can_abandon(curbuf, forceit))
1253 {
1254 EMSG(_(e_nowrtmsg));
1255 ok = FALSE;
1256 }
1257 else
1258 ok = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1,
1259 ECMD_HIDE + ECMD_SET_HELP);
1260 }
1261 else
1262 ok = buflist_getfile(qf_ptr->qf_fnum,
1263 (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit);
1264 }
1265
1266 if (ok == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001267 {
1268 /* When not switched to another buffer, still need to set pc mark */
1269 if (curbuf == old_curbuf)
1270 setpcmark();
1271
1272 /*
1273 * Go to line with error, unless qf_lnum is 0.
1274 */
1275 i = qf_ptr->qf_lnum;
1276 if (i > 0)
1277 {
1278 if (i > curbuf->b_ml.ml_line_count)
1279 i = curbuf->b_ml.ml_line_count;
1280 curwin->w_cursor.lnum = i;
1281 }
1282 if (qf_ptr->qf_col > 0)
1283 {
1284 curwin->w_cursor.col = qf_ptr->qf_col - 1;
1285 if (qf_ptr->qf_virt_col == TRUE)
1286 {
1287 /*
1288 * Check each character from the beginning of the error
1289 * line up to the error column. For each tab character
1290 * found, reduce the error column value by the length of
1291 * a tab character.
1292 */
1293 line = ml_get_curline();
1294 screen_col = 0;
1295 for (char_col = 0; char_col < curwin->w_cursor.col; ++char_col)
1296 {
1297 if (*line == NUL)
1298 break;
1299 if (*line++ == '\t')
1300 {
1301 curwin->w_cursor.col -= 7 - (screen_col % 8);
1302 screen_col += 8 - (screen_col % 8);
1303 }
1304 else
1305 ++screen_col;
1306 }
1307 }
1308 check_cursor();
1309 }
1310 else
1311 beginline(BL_WHITE | BL_FIX);
1312
1313#ifdef FEAT_FOLDING
1314 if ((fdo_flags & FDO_QUICKFIX) && old_KeyTyped)
1315 foldOpenCursor();
1316#endif
1317 if (print_message)
1318 {
1319 /* Update the screen before showing the message */
1320 update_topline_redraw();
1321 sprintf((char *)IObuff, _("(%d of %d)%s%s: "), qf_index,
1322 qf_lists[qf_curlist].qf_count,
1323 qf_ptr->qf_cleared ? _(" (line deleted)") : "",
1324 (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
1325 /* Add the message, skipping leading whitespace and newlines. */
1326 len = (int)STRLEN(IObuff);
1327 qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len);
1328
1329 /* Output the message. Overwrite to avoid scrolling when the 'O'
1330 * flag is present in 'shortmess'; But when not jumping, print the
1331 * whole message. */
1332 i = msg_scroll;
1333 if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum)
1334 msg_scroll = TRUE;
1335 else if (!msg_scrolled && shortmess(SHM_OVERALL))
1336 msg_scroll = FALSE;
1337 msg_attr_keep(IObuff, 0, TRUE);
1338 msg_scroll = i;
1339 }
1340 }
1341 else
1342 {
1343#ifdef FEAT_WINDOWS
1344 if (opened_window)
1345 win_close(curwin, TRUE); /* Close opened window */
1346#endif
1347 if (qf_ptr->qf_fnum != 0)
1348 {
1349 /*
1350 * Couldn't open file, so put index back where it was. This could
1351 * happen if the file was readonly and we changed something.
1352 */
1353#ifdef FEAT_WINDOWS
1354failed:
1355#endif
1356 qf_ptr = old_qf_ptr;
1357 qf_index = old_qf_index;
1358 }
1359 }
1360theend:
1361 qf_lists[qf_curlist].qf_ptr = qf_ptr;
1362 qf_lists[qf_curlist].qf_index = qf_index;
1363#ifdef FEAT_WINDOWS
1364 if (p_swb != old_swb && opened_window)
1365 {
1366 /* Restore old 'switchbuf' value, but not when an autocommand or
1367 * modeline has changed the value. */
1368 if (p_swb == empty_option)
1369 p_swb = old_swb;
1370 else
1371 free_string_option(old_swb);
1372 }
1373#endif
1374}
1375
1376/*
1377 * ":clist": list all errors
1378 */
1379 void
1380qf_list(eap)
1381 exarg_T *eap;
1382{
1383 buf_T *buf;
1384 char_u *fname;
1385 struct qf_line *qfp;
1386 int i;
1387 int idx1 = 1;
1388 int idx2 = -1;
1389 int need_return = TRUE;
1390 int last_printed = 1;
1391 char_u *arg = eap->arg;
1392 int all = eap->forceit; /* if not :cl!, only show
1393 recognised errors */
1394
1395 if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0)
1396 {
1397 EMSG(_(e_quickfix));
1398 return;
1399 }
1400 if (!get_list_range(&arg, &idx1, &idx2) || *arg != NUL)
1401 {
1402 EMSG(_(e_trailing));
1403 return;
1404 }
1405 i = qf_lists[qf_curlist].qf_count;
1406 if (idx1 < 0)
1407 idx1 = (-idx1 > i) ? 0 : idx1 + i + 1;
1408 if (idx2 < 0)
1409 idx2 = (-idx2 > i) ? 0 : idx2 + i + 1;
1410
1411 more_back_used = TRUE;
1412 if (qf_lists[qf_curlist].qf_nonevalid)
1413 all = TRUE;
1414 qfp = qf_lists[qf_curlist].qf_start;
1415 for (i = 1; !got_int && i <= qf_lists[qf_curlist].qf_count; )
1416 {
1417 if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2)
1418 {
1419 if (need_return)
1420 {
1421 msg_putchar('\n');
1422 need_return = FALSE;
1423 }
1424 if (more_back == 0)
1425 {
1426 fname = NULL;
1427 if (qfp->qf_fnum != 0
1428 && (buf = buflist_findnr(qfp->qf_fnum)) != NULL)
1429 {
1430 fname = buf->b_fname;
1431 if (qfp->qf_type == 1) /* :helpgrep */
1432 fname = gettail(fname);
1433 }
1434 if (fname == NULL)
1435 sprintf((char *)IObuff, "%2d", i);
1436 else
1437 sprintf((char *)IObuff, "%2d %s", i, (char *)fname);
1438 msg_outtrans_attr(IObuff, i == qf_lists[qf_curlist].qf_index
1439 ? hl_attr(HLF_L) : hl_attr(HLF_D));
1440 if (qfp->qf_lnum == 0)
1441 IObuff[0] = NUL;
1442 else if (qfp->qf_col == 0)
1443 sprintf((char *)IObuff, ":%ld", qfp->qf_lnum);
1444 else
1445 sprintf((char *)IObuff, ":%ld col %d",
1446 qfp->qf_lnum, qfp->qf_col);
1447 sprintf((char *)IObuff + STRLEN(IObuff), "%s: ",
1448 (char *)qf_types(qfp->qf_type, qfp->qf_nr));
1449 msg_puts_attr(IObuff, hl_attr(HLF_N));
1450 /* Remove newlines and leading whitespace from the text.
1451 * For an unrecognized line keep the indent, the compiler may
1452 * mark a word with ^^^^. */
1453 qf_fmt_text((fname != NULL || qfp->qf_lnum != 0)
1454 ? skipwhite(qfp->qf_text) : qfp->qf_text,
1455 IObuff, IOSIZE);
1456 msg_prt_line(IObuff);
1457 out_flush(); /* show one line at a time */
1458 need_return = TRUE;
1459 last_printed = i;
1460 }
1461 }
1462 if (more_back)
1463 {
1464 /* scrolling backwards from the more-prompt */
1465 /* TODO: compute the number of items from the screen lines */
1466 more_back = more_back * 2 - 1;
1467 while (i > last_printed - more_back && i > idx1)
1468 {
1469 do
1470 {
1471 qfp = qfp->qf_prev;
1472 --i;
1473 }
1474 while (i > idx1 && !qfp->qf_valid && !all);
1475 }
1476 more_back = 0;
1477 }
1478 else
1479 {
1480 qfp = qfp->qf_next;
1481 ++i;
1482 }
1483 ui_breakcheck();
1484 }
1485 more_back_used = FALSE;
1486}
1487
1488/*
1489 * Remove newlines and leading whitespace from an error message.
1490 * Put the result in "buf[bufsize]".
1491 */
1492 static void
1493qf_fmt_text(text, buf, bufsize)
1494 char_u *text;
1495 char_u *buf;
1496 int bufsize;
1497{
1498 int i;
1499 char_u *p = text;
1500
1501 for (i = 0; *p != NUL && i < bufsize - 1; ++i)
1502 {
1503 if (*p == '\n')
1504 {
1505 buf[i] = ' ';
1506 while (*++p != NUL)
1507 if (!vim_iswhite(*p) && *p != '\n')
1508 break;
1509 }
1510 else
1511 buf[i] = *p++;
1512 }
1513 buf[i] = NUL;
1514}
1515
1516/*
1517 * ":colder [count]": Up in the quickfix stack.
1518 * ":cnewer [count]": Down in the quickfix stack.
1519 */
1520 void
1521qf_age(eap)
1522 exarg_T *eap;
1523{
1524 int count;
1525
1526 if (eap->addr_count != 0)
1527 count = eap->line2;
1528 else
1529 count = 1;
1530 while (count--)
1531 {
1532 if (eap->cmdidx == CMD_colder)
1533 {
1534 if (qf_curlist == 0)
1535 {
1536 EMSG(_("E380: At bottom of quickfix stack"));
1537 return;
1538 }
1539 --qf_curlist;
1540 }
1541 else
1542 {
1543 if (qf_curlist >= qf_listcount - 1)
1544 {
1545 EMSG(_("E381: At top of quickfix stack"));
1546 return;
1547 }
1548 ++qf_curlist;
1549 }
1550 }
1551 qf_msg();
1552}
1553
1554 static void
1555qf_msg()
1556{
1557 smsg((char_u *)_("error list %d of %d; %d errors"),
1558 qf_curlist + 1, qf_listcount, qf_lists[qf_curlist].qf_count);
1559#ifdef FEAT_WINDOWS
1560 qf_update_buffer();
1561#endif
1562}
1563
1564/*
1565 * free the error list
1566 */
1567 static void
1568qf_free(idx)
1569 int idx;
1570{
1571 struct qf_line *qfp;
1572
1573 while (qf_lists[idx].qf_count)
1574 {
1575 qfp = qf_lists[idx].qf_start->qf_next;
1576 vim_free(qf_lists[idx].qf_start->qf_text);
1577 vim_free(qf_lists[idx].qf_start);
1578 qf_lists[idx].qf_start = qfp;
1579 --qf_lists[idx].qf_count;
1580 }
1581}
1582
1583/*
1584 * qf_mark_adjust: adjust marks
1585 */
1586 void
1587qf_mark_adjust(line1, line2, amount, amount_after)
1588 linenr_T line1;
1589 linenr_T line2;
1590 long amount;
1591 long amount_after;
1592{
1593 int i;
1594 struct qf_line *qfp;
1595 int idx;
1596
1597 for (idx = 0; idx < qf_listcount; ++idx)
1598 if (qf_lists[idx].qf_count)
1599 for (i = 0, qfp = qf_lists[idx].qf_start;
1600 i < qf_lists[idx].qf_count; ++i, qfp = qfp->qf_next)
1601 if (qfp->qf_fnum == curbuf->b_fnum)
1602 {
1603 if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2)
1604 {
1605 if (amount == MAXLNUM)
1606 qfp->qf_cleared = TRUE;
1607 else
1608 qfp->qf_lnum += amount;
1609 }
1610 else if (amount_after && qfp->qf_lnum > line2)
1611 qfp->qf_lnum += amount_after;
1612 }
1613}
1614
1615/*
1616 * Make a nice message out of the error character and the error number:
1617 * char number message
1618 * e or E 0 " error"
1619 * w or W 0 " warning"
1620 * i or I 0 " info"
1621 * 0 0 ""
1622 * other 0 " c"
1623 * e or E n " error n"
1624 * w or W n " warning n"
1625 * i or I n " info n"
1626 * 0 n " error n"
1627 * other n " c n"
1628 * 1 x "" :helpgrep
1629 */
1630 static char_u *
1631qf_types(c, nr)
1632 int c, nr;
1633{
1634 static char_u buf[20];
1635 static char_u cc[3];
1636 char_u *p;
1637
1638 if (c == 'W' || c == 'w')
1639 p = (char_u *)" warning";
1640 else if (c == 'I' || c == 'i')
1641 p = (char_u *)" info";
1642 else if (c == 'E' || c == 'e' || (c == 0 && nr > 0))
1643 p = (char_u *)" error";
1644 else if (c == 0 || c == 1)
1645 p = (char_u *)"";
1646 else
1647 {
1648 cc[0] = ' ';
1649 cc[1] = c;
1650 cc[2] = NUL;
1651 p = cc;
1652 }
1653
1654 if (nr <= 0)
1655 return p;
1656
1657 sprintf((char *)buf, "%s %3d", (char *)p, nr);
1658 return buf;
1659}
1660
1661#if defined(FEAT_WINDOWS) || defined(PROTO)
1662/*
1663 * ":cwindow": open the quickfix window if we have errors to display,
1664 * close it if not.
1665 */
1666 void
1667ex_cwindow(eap)
1668 exarg_T *eap;
1669{
1670 win_T *win;
1671
1672 /*
1673 * Look for an existing quickfix window.
1674 */
1675 for (win = firstwin; win != NULL; win = win->w_next)
1676 if (bt_quickfix(win->w_buffer))
1677 break;
1678
1679 /*
1680 * If a quickfix window is open but we have no errors to display,
1681 * close the window. If a quickfix window is not open, then open
1682 * it if we have errors; otherwise, leave it closed.
1683 */
1684 if (qf_lists[qf_curlist].qf_nonevalid || qf_curlist >= qf_listcount)
1685 {
1686 if (win != NULL)
1687 ex_cclose(eap);
1688 }
1689 else if (win == NULL)
1690 ex_copen(eap);
1691}
1692
1693/*
1694 * ":cclose": close the window showing the list of errors.
1695 */
1696/*ARGSUSED*/
1697 void
1698ex_cclose(eap)
1699 exarg_T *eap;
1700{
1701 win_T *win;
1702
1703 /*
1704 * Find existing quickfix window and close it.
1705 */
1706 for (win = firstwin; win != NULL; win = win->w_next)
1707 if (bt_quickfix(win->w_buffer))
1708 break;
1709
1710 if (win != NULL)
1711 win_close(win, FALSE);
1712}
1713
1714/*
1715 * ":copen": open a window that shows the list of errors.
1716 */
1717 void
1718ex_copen(eap)
1719 exarg_T *eap;
1720{
1721 int height;
1722 buf_T *buf;
1723 win_T *win;
1724
1725 if (eap->addr_count != 0)
1726 height = eap->line2;
1727 else
1728 height = QF_WINHEIGHT;
1729
1730#ifdef FEAT_VISUAL
1731 reset_VIsual_and_resel(); /* stop Visual mode */
1732#endif
1733#ifdef FEAT_GUI
1734 need_mouse_correct = TRUE;
1735#endif
1736
1737 /*
1738 * Find existing quickfix window, or open a new one.
1739 */
1740 for (win = firstwin; win != NULL; win = win->w_next)
1741 if (bt_quickfix(win->w_buffer))
1742 break;
1743 if (win != NULL)
1744 win_goto(win);
1745 else
1746 {
1747 /* The current window becomes the previous window afterwards. */
1748 win = curwin;
1749
1750 /* Create the new window at the very bottom. */
1751 win_goto(lastwin);
1752 if (win_split(height, WSP_BELOW) == FAIL)
1753 return; /* not enough room for window */
1754#ifdef FEAT_SCROLLBIND
1755 curwin->w_p_scb = FALSE;
1756#endif
1757
1758 /*
1759 * Find existing quickfix buffer, or create a new one.
1760 */
1761 buf = qf_find_buf();
1762 if (buf == NULL)
1763 {
1764 (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE);
1765 /* switch off 'swapfile' */
1766 set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
1767 set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix",
1768 OPT_LOCAL);
1769 set_option_value((char_u *)"bh", 0L, (char_u *)"delete", OPT_LOCAL);
1770 set_option_value((char_u *)"diff", 0L, (char_u *)"", OPT_LOCAL);
1771 }
1772 else if (buf != curbuf)
1773 set_curbuf(buf, DOBUF_GOTO);
1774
1775 /* Only set the height when there is no window to the side. */
1776 if (curwin->w_width == Columns)
1777 win_setheight(height);
1778 curwin->w_p_wfh = TRUE; /* set 'winfixheight' */
1779 if (win_valid(win))
1780 prevwin = win;
1781 }
1782
1783 /*
1784 * Fill the buffer with the quickfix list.
1785 */
1786 qf_fill_buffer();
1787
1788 curwin->w_cursor.lnum = qf_lists[qf_curlist].qf_index;
1789 curwin->w_cursor.col = 0;
1790 check_cursor();
1791 update_topline(); /* scroll to show the line */
1792}
1793
1794/*
1795 * Return the number of the current entry (line number in the quickfix
1796 * window).
1797 */
1798 linenr_T
1799qf_current_entry()
1800{
1801 return qf_lists[qf_curlist].qf_index;
1802}
1803
1804/*
1805 * Update the cursor position in the quickfix window to the current error.
1806 * Return TRUE if there is a quickfix window.
1807 */
1808 static int
1809qf_win_pos_update(old_qf_index)
1810 int old_qf_index; /* previous qf_index or zero */
1811{
1812 win_T *win;
1813 int qf_index = qf_lists[qf_curlist].qf_index;
1814
1815 /*
1816 * Put the cursor on the current error in the quickfix window, so that
1817 * it's viewable.
1818 */
1819 for (win = firstwin; win != NULL; win = win->w_next)
1820 if (bt_quickfix(win->w_buffer))
1821 break;
1822 if (win != NULL
1823 && qf_index <= win->w_buffer->b_ml.ml_line_count
1824 && old_qf_index != qf_index)
1825 {
1826 win_T *old_curwin = curwin;
1827
1828 curwin = win;
1829 curbuf = win->w_buffer;
1830 if (qf_index > old_qf_index)
1831 {
1832 curwin->w_redraw_top = old_qf_index;
1833 curwin->w_redraw_bot = qf_index;
1834 }
1835 else
1836 {
1837 curwin->w_redraw_top = qf_index;
1838 curwin->w_redraw_bot = old_qf_index;
1839 }
1840 curwin->w_cursor.lnum = qf_index;
1841 curwin->w_cursor.col = 0;
1842 update_topline(); /* scroll to show the line */
1843 redraw_later(VALID);
1844 curwin->w_redr_status = TRUE; /* update ruler */
1845 curwin = old_curwin;
1846 curbuf = curwin->w_buffer;
1847 }
1848 return win != NULL;
1849}
1850
1851/*
1852 * Find quickfix buffer.
1853 */
1854 static buf_T *
1855qf_find_buf()
1856{
1857 buf_T *buf;
1858
1859 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1860 if (bt_quickfix(buf))
1861 break;
1862 return buf;
1863}
1864
1865/*
1866 * Find the quickfix buffer. If it exists, update the contents.
1867 */
1868 static void
1869qf_update_buffer()
1870{
1871 buf_T *buf;
1872#ifdef FEAT_AUTOCMD
1873 aco_save_T aco;
1874#else
1875 buf_T *save_curbuf;
1876#endif
1877
1878 /* Check if a buffer for the quickfix list exists. Update it. */
1879 buf = qf_find_buf();
1880 if (buf != NULL)
1881 {
1882#ifdef FEAT_AUTOCMD
1883 /* set curwin/curbuf to buf and save a few things */
1884 aucmd_prepbuf(&aco, buf);
1885#else
1886 save_curbuf = curbuf;
1887 curbuf = buf;
1888#endif
1889
1890 qf_fill_buffer();
1891
1892#ifdef FEAT_AUTOCMD
1893 /* restore curwin/curbuf and a few other things */
1894 aucmd_restbuf(&aco);
1895#else
1896 curbuf = save_curbuf;
1897#endif
1898
1899 (void)qf_win_pos_update(0);
1900 }
1901}
1902
1903/*
1904 * Fill current buffer with quickfix errors, replacing any previous contents.
1905 * curbuf must be the quickfix buffer!
1906 */
1907 static void
1908qf_fill_buffer()
1909{
1910 linenr_T lnum;
1911 struct qf_line *qfp;
1912 buf_T *errbuf;
1913 int len;
1914 int old_KeyTyped = KeyTyped;
1915
1916 /* delete all existing lines */
1917 while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0)
1918 (void)ml_delete((linenr_T)1, FALSE);
1919
1920 /* Check if there is anything to display */
1921 if (qf_curlist < qf_listcount)
1922 {
1923 /* Add one line for each error */
1924 qfp = qf_lists[qf_curlist].qf_start;
1925 for (lnum = 0; lnum < qf_lists[qf_curlist].qf_count; ++lnum)
1926 {
1927 if (qfp->qf_fnum != 0
1928 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
1929 && errbuf->b_fname != NULL)
1930 {
1931 if (qfp->qf_type == 1) /* :helpgrep */
1932 STRCPY(IObuff, gettail(errbuf->b_fname));
1933 else
1934 STRCPY(IObuff, errbuf->b_fname);
1935 len = (int)STRLEN(IObuff);
1936 }
1937 else
1938 len = 0;
1939 IObuff[len++] = '|';
1940
1941 if (qfp->qf_lnum > 0)
1942 {
1943 sprintf((char *)IObuff + len, "%ld", qfp->qf_lnum);
1944 len += (int)STRLEN(IObuff + len);
1945
1946 if (qfp->qf_col > 0)
1947 {
1948 sprintf((char *)IObuff + len, " col %d", qfp->qf_col);
1949 len += (int)STRLEN(IObuff + len);
1950 }
1951
1952 sprintf((char *)IObuff + len, "%s",
1953 (char *)qf_types(qfp->qf_type, qfp->qf_nr));
1954 len += (int)STRLEN(IObuff + len);
1955 }
1956 IObuff[len++] = '|';
1957 IObuff[len++] = ' ';
1958
1959 /* Remove newlines and leading whitespace from the text.
1960 * For an unrecognized line keep the indent, the compiler may
1961 * mark a word with ^^^^. */
1962 qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text,
1963 IObuff + len, IOSIZE - len);
1964
1965 if (ml_append(lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, FALSE)
1966 == FAIL)
1967 break;
1968 qfp = qfp->qf_next;
1969 }
1970 /* Delete the empty line which is now at the end */
1971 (void)ml_delete(lnum + 1, FALSE);
1972 }
1973
1974 /* correct cursor position */
1975 check_lnums(TRUE);
1976
1977 /* Set the 'filetype' to "qf" each time after filling the buffer. This
1978 * resembles reading a file into a buffer, it's more logical when using
1979 * autocommands. */
1980 set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL);
1981 curbuf->b_p_ma = FALSE;
1982
1983#ifdef FEAT_AUTOCMD
1984 apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL,
1985 FALSE, curbuf);
1986 apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL,
1987 FALSE, curbuf);
1988#endif
1989
1990 /* make sure it will be redrawn */
1991 redraw_curbuf_later(NOT_VALID);
1992
1993 /* Restore KeyTyped, setting 'filetype' may reset it. */
1994 KeyTyped = old_KeyTyped;
1995}
1996
1997#endif /* FEAT_WINDOWS */
1998
1999/*
2000 * Return TRUE if "buf" is the quickfix buffer.
2001 */
2002 int
2003bt_quickfix(buf)
2004 buf_T *buf;
2005{
2006 return (buf->b_p_bt[0] == 'q');
2007}
2008
2009/*
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002010 * Return TRUE if "buf" is a "nofile" or "acwrite" buffer.
2011 * This means the buffer name is not a file name.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002012 */
2013 int
2014bt_nofile(buf)
2015 buf_T *buf;
2016{
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002017 return (buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f')
2018 || buf->b_p_bt[0] == 'a';
Bram Moolenaar071d4272004-06-13 20:20:40 +00002019}
2020
2021/*
2022 * Return TRUE if "buf" is a "nowrite" or "nofile" buffer.
2023 */
2024 int
2025bt_dontwrite(buf)
2026 buf_T *buf;
2027{
2028 return (buf->b_p_bt[0] == 'n');
2029}
2030
2031 int
2032bt_dontwrite_msg(buf)
2033 buf_T *buf;
2034{
2035 if (bt_dontwrite(buf))
2036 {
2037 EMSG(_("E382: Cannot write, 'buftype' option is set"));
2038 return TRUE;
2039 }
2040 return FALSE;
2041}
2042
2043/*
2044 * Return TRUE if the buffer should be hidden, according to 'hidden', ":hide"
2045 * and 'bufhidden'.
2046 */
2047 int
2048buf_hide(buf)
2049 buf_T *buf;
2050{
2051 /* 'bufhidden' overrules 'hidden' and ":hide", check it first */
2052 switch (buf->b_p_bh[0])
2053 {
2054 case 'u': /* "unload" */
2055 case 'w': /* "wipe" */
2056 case 'd': return FALSE; /* "delete" */
2057 case 'h': return TRUE; /* "hide" */
2058 }
2059 return (p_hid || cmdmod.hide);
2060}
2061
2062/*
Bram Moolenaar86b68352004-12-27 21:59:20 +00002063 * Return TRUE when using ":vimgrep" for ":grep".
2064 */
2065 int
2066grep_internal(eap)
2067 exarg_T *eap;
2068{
2069 return ((eap->cmdidx == CMD_grep || eap->cmdidx == CMD_grepadd)
2070 && STRCMP("internal",
2071 *curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0);
2072}
2073
2074/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002075 * Used for ":make", ":grep" and ":grepadd".
2076 */
2077 void
2078ex_make(eap)
2079 exarg_T *eap;
2080{
2081 char_u *name;
2082 char_u *cmd;
2083 unsigned len;
2084
Bram Moolenaar86b68352004-12-27 21:59:20 +00002085 /* Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal". */
2086 if (grep_internal(eap))
2087 {
2088 ex_vimgrep(eap);
2089 return;
2090 }
2091
Bram Moolenaar071d4272004-06-13 20:20:40 +00002092 autowrite_all();
2093 name = get_mef_name();
2094 if (name == NULL)
2095 return;
2096 mch_remove(name); /* in case it's not unique */
2097
2098 /*
2099 * If 'shellpipe' empty: don't redirect to 'errorfile'.
2100 */
2101 len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(eap->arg) + 1;
2102 if (*p_sp != NUL)
2103 len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(name) + 3;
2104 cmd = alloc(len);
2105 if (cmd == NULL)
2106 return;
2107 sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)eap->arg,
2108 (char *)p_shq);
2109 if (*p_sp != NUL)
2110 append_redir(cmd, p_sp, name);
2111 /*
2112 * Output a newline if there's something else than the :make command that
2113 * was typed (in which case the cursor is in column 0).
2114 */
2115 if (msg_col == 0)
2116 msg_didout = FALSE;
2117 msg_start();
2118 MSG_PUTS(":!");
2119 msg_outtrans(cmd); /* show what we are doing */
2120
2121 /* let the shell know if we are redirecting output or not */
2122 do_shell(cmd, *p_sp != NUL ? SHELL_DOOUT : 0);
2123
2124#ifdef AMIGA
2125 out_flush();
2126 /* read window status report and redraw before message */
2127 (void)char_avail();
2128#endif
2129
2130 if (qf_init(name, eap->cmdidx != CMD_make ? p_gefm : p_efm,
Bram Moolenaar86b68352004-12-27 21:59:20 +00002131 eap->cmdidx != CMD_grepadd) > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002132 && !eap->forceit)
2133 qf_jump(0, 0, FALSE); /* display first error */
2134
2135 mch_remove(name);
2136 vim_free(name);
2137 vim_free(cmd);
2138}
2139
2140/*
2141 * Return the name for the errorfile, in allocated memory.
2142 * Find a new unique name when 'makeef' contains "##".
2143 * Returns NULL for error.
2144 */
2145 static char_u *
2146get_mef_name()
2147{
2148 char_u *p;
2149 char_u *name;
2150 static int start = -1;
2151 static int off = 0;
2152#ifdef HAVE_LSTAT
2153 struct stat sb;
2154#endif
2155
2156 if (*p_mef == NUL)
2157 {
2158 name = vim_tempname('e');
2159 if (name == NULL)
2160 EMSG(_(e_notmp));
2161 return name;
2162 }
2163
2164 for (p = p_mef; *p; ++p)
2165 if (p[0] == '#' && p[1] == '#')
2166 break;
2167
2168 if (*p == NUL)
2169 return vim_strsave(p_mef);
2170
2171 /* Keep trying until the name doesn't exist yet. */
2172 for (;;)
2173 {
2174 if (start == -1)
2175 start = mch_get_pid();
2176 else
2177 off += 19;
2178
2179 name = alloc((unsigned)STRLEN(p_mef) + 30);
2180 if (name == NULL)
2181 break;
2182 STRCPY(name, p_mef);
2183 sprintf((char *)name + (p - p_mef), "%d%d", start, off);
2184 STRCAT(name, p + 2);
2185 if (mch_getperm(name) < 0
2186#ifdef HAVE_LSTAT
2187 /* Don't accept a symbolic link, its a security risk. */
2188 && mch_lstat((char *)name, &sb) < 0
2189#endif
2190 )
2191 break;
2192 vim_free(name);
2193 }
2194 return name;
2195}
2196
2197/*
2198 * ":cc", ":crewind", ":cfirst" and ":clast".
2199 */
2200 void
2201ex_cc(eap)
2202 exarg_T *eap;
2203{
2204 qf_jump(0,
2205 eap->addr_count > 0
2206 ? (int)eap->line2
2207 : eap->cmdidx == CMD_cc
2208 ? 0
2209 : (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_cfirst)
2210 ? 1
2211 : 32767,
2212 eap->forceit);
2213}
2214
2215/*
2216 * ":cnext", ":cnfile", ":cNext" and ":cprevious".
2217 */
2218 void
2219ex_cnext(eap)
2220 exarg_T *eap;
2221{
2222 qf_jump(eap->cmdidx == CMD_cnext
2223 ? FORWARD
2224 : eap->cmdidx == CMD_cnfile
2225 ? FORWARD_FILE
2226 : (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_cNfile)
2227 ? BACKWARD_FILE
2228 : BACKWARD,
2229 eap->addr_count > 0 ? (int)eap->line2 : 1, eap->forceit);
2230}
2231
2232/*
2233 * ":cfile" command.
2234 */
2235 void
2236ex_cfile(eap)
2237 exarg_T *eap;
2238{
2239 if (*eap->arg != NUL)
2240 set_string_option_direct((char_u *)"ef", -1, eap->arg, OPT_FREE);
2241 if (qf_init(p_ef, p_efm, TRUE) > 0 && eap->cmdidx == CMD_cfile)
2242 qf_jump(0, 0, eap->forceit); /* display first error */
2243}
2244
2245/*
Bram Moolenaar86b68352004-12-27 21:59:20 +00002246 * ":vimgrep {pattern} file(s)"
2247 */
2248 void
2249ex_vimgrep(eap)
2250 exarg_T *eap;
2251{
2252 regmatch_T regmatch;
2253 char_u *save_cpo;
2254 int fcount;
2255 char_u **fnames;
2256 char_u *p;
2257 int i;
2258 FILE *fd;
2259 int fi;
2260 struct qf_line *prevp = NULL;
2261 long lnum;
2262 garray_T ga;
2263
2264 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
2265 save_cpo = p_cpo;
2266 p_cpo = empty_option;
2267
2268 /* Get the search pattern */
2269 regmatch.regprog = NULL;
2270 p = skip_regexp(eap->arg + 1, *eap->arg, TRUE, NULL);
2271 if (*p != *eap->arg)
2272 {
2273 EMSG(_("E682: Invalid search pattern or delimiter"));
2274 goto theend;
2275 }
2276 *p++ = NUL;
2277 regmatch.regprog = vim_regcomp(eap->arg + 1, RE_MAGIC);
2278 if (regmatch.regprog == NULL)
2279 goto theend;
2280 regmatch.rm_ic = FALSE;
2281
2282 p = skipwhite(p);
2283 if (*p == NUL)
2284 {
2285 EMSG(_("E683: File name missing or invalid pattern"));
2286 goto theend;
2287 }
2288
2289 if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_vimgrepadd)
2290 || qf_curlist == qf_listcount)
2291 /* make place for a new list */
2292 qf_new_list();
2293 else if (qf_lists[qf_curlist].qf_count > 0)
2294 /* Adding to existing list, find last entry. */
2295 for (prevp = qf_lists[qf_curlist].qf_start;
2296 prevp->qf_next != prevp; prevp = prevp->qf_next)
2297 ;
2298
2299 /* parse the list of arguments */
2300 if (get_arglist(&ga, p) == FAIL)
2301 goto theend;
2302 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2303 &fcount, &fnames, EW_FILE|EW_NOTFOUND);
2304 ga_clear(&ga);
2305 if (i == FAIL)
2306 goto theend;
2307 if (fcount == 0)
2308 {
2309 EMSG(_(e_nomatch));
2310 goto theend;
2311 }
2312
2313 for (fi = 0; fi < fcount && !got_int; ++fi)
2314 {
2315 fd = fopen((char *)fnames[fi], "r");
2316 if (fd == NULL)
2317 smsg((char_u *)_("Cannot open file \"%s\""), fnames[fi]);
2318 else
2319 {
2320 lnum = 1;
2321 while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int)
2322 {
2323 if (vim_regexec(&regmatch, IObuff, (colnr_T)0))
2324 {
2325 int l = STRLEN(IObuff);
2326
2327 /* remove trailing CR, LF, spaces, etc. */
2328 while (l > 0 && IObuff[l - 1] <= ' ')
2329 IObuff[--l] = NUL;
2330
2331 if (qf_add_entry(&prevp,
2332 NULL, /* dir */
2333 fnames[fi],
2334 IObuff,
2335 lnum,
2336 (int)(regmatch.startp[0] - IObuff) + 1,/* col */
2337 FALSE, /* virt_col */
2338 0, /* nr */
2339 0, /* type */
2340 TRUE /* valid */
2341 ) == FAIL)
2342 {
2343 got_int = TRUE;
2344 break;
2345 }
2346 }
2347 ++lnum;
2348 line_breakcheck();
2349 }
2350 fclose(fd);
2351 }
2352 }
2353
2354 FreeWild(fcount, fnames);
2355
2356 qf_lists[qf_curlist].qf_nonevalid = FALSE;
2357 qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start;
2358 qf_lists[qf_curlist].qf_index = 1;
2359
2360#ifdef FEAT_WINDOWS
2361 qf_update_buffer();
2362#endif
2363
2364 /* Jump to first match. */
2365 if (qf_lists[qf_curlist].qf_count > 0)
2366 qf_jump(0, 0, FALSE);
2367
2368theend:
2369 vim_free(regmatch.regprog);
2370
2371 /* Only resture 'cpo' when it wasn't set in the mean time. */
2372 if (p_cpo == empty_option)
2373 p_cpo = save_cpo;
2374 else
2375 free_string_option(save_cpo);
2376}
2377
2378/*
2379 * ":[range]cbuffer [bufnr]" command.
2380 */
2381 void
2382ex_cbuffer(eap)
2383 exarg_T *eap;
2384{
2385 buf_T *buf = NULL;
2386
2387 if (*eap->arg == NUL)
2388 buf = curbuf;
2389 else if (*skipwhite(skipdigits(eap->arg)) == NUL)
2390 buf = buflist_findnr(atoi((char *)eap->arg));
2391 if (buf == NULL)
2392 EMSG(_(e_invarg));
2393 else if (buf->b_ml.ml_mfp == NULL)
2394 EMSG(_("E681: Buffer is not loaded"));
2395 else
2396 {
2397 if (eap->addr_count == 0)
2398 {
2399 eap->line1 = 1;
2400 eap->line2 = buf->b_ml.ml_line_count;
2401 }
2402 if (eap->line1 < 1 || eap->line1 > buf->b_ml.ml_line_count
2403 || eap->line2 < 1 || eap->line2 > buf->b_ml.ml_line_count)
2404 EMSG(_(e_invrange));
2405 else
2406 qf_init_ext(NULL, buf, p_efm, TRUE, eap->line1, eap->line2);
2407 }
2408}
2409
2410/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002411 * ":helpgrep {pattern}"
2412 */
2413 void
2414ex_helpgrep(eap)
2415 exarg_T *eap;
2416{
2417 regmatch_T regmatch;
2418 char_u *save_cpo;
2419 char_u *p;
2420 int fcount;
2421 char_u **fnames;
2422 FILE *fd;
2423 int fi;
2424 struct qf_line *prevp = NULL;
2425 long lnum;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002426#ifdef FEAT_MULTI_LANG
2427 char_u *lang;
2428#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002429
2430 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
2431 save_cpo = p_cpo;
2432 p_cpo = (char_u *)"";
2433
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002434#ifdef FEAT_MULTI_LANG
2435 /* Check for a specified language */
2436 lang = check_help_lang(eap->arg);
2437#endif
2438
Bram Moolenaar071d4272004-06-13 20:20:40 +00002439 regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING);
2440 regmatch.rm_ic = FALSE;
2441 if (regmatch.regprog != NULL)
2442 {
2443 /* create a new quickfix list */
2444 qf_new_list();
2445
2446 /* Go through all directories in 'runtimepath' */
2447 p = p_rtp;
2448 while (*p != NUL && !got_int)
2449 {
2450 copy_option_part(&p, NameBuff, MAXPATHL, ",");
2451
2452 /* Find all "*.txt" and "*.??x" files in the "doc" directory. */
2453 add_pathsep(NameBuff);
2454 STRCAT(NameBuff, "doc/*.\\(txt\\|??x\\)");
2455 if (gen_expand_wildcards(1, &NameBuff, &fcount,
2456 &fnames, EW_FILE|EW_SILENT) == OK
2457 && fcount > 0)
2458 {
2459 for (fi = 0; fi < fcount && !got_int; ++fi)
2460 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002461#ifdef FEAT_MULTI_LANG
2462 /* Skip files for a different language. */
2463 if (lang != NULL
2464 && STRNICMP(lang, fnames[fi]
2465 + STRLEN(fnames[fi]) - 3, 2) != 0
2466 && !(STRNICMP(lang, "en", 2) == 0
2467 && STRNICMP("txt", fnames[fi]
2468 + STRLEN(fnames[fi]) - 3, 3) == 0))
2469 continue;
2470#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002471 fd = fopen((char *)fnames[fi], "r");
2472 if (fd != NULL)
2473 {
2474 lnum = 1;
2475 while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int)
2476 {
2477 if (vim_regexec(&regmatch, IObuff, (colnr_T)0))
2478 {
2479 int l = STRLEN(IObuff);
2480
2481 /* remove trailing CR, LF, spaces, etc. */
2482 while (l > 0 && IObuff[l - 1] <= ' ')
2483 IObuff[--l] = NUL;
2484
2485 if (qf_add_entry(&prevp,
2486 NULL, /* dir */
2487 fnames[fi],
2488 IObuff,
2489 lnum,
2490 0, /* col */
2491 FALSE, /* virt_col */
2492 0, /* nr */
2493 1, /* type */
2494 TRUE /* valid */
2495 ) == FAIL)
2496 {
2497 got_int = TRUE;
2498 break;
2499 }
2500 }
2501 ++lnum;
2502 line_breakcheck();
2503 }
2504 fclose(fd);
2505 }
2506 }
2507 FreeWild(fcount, fnames);
2508 }
2509 }
2510 vim_free(regmatch.regprog);
2511
2512 qf_lists[qf_curlist].qf_nonevalid = FALSE;
2513 qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start;
2514 qf_lists[qf_curlist].qf_index = 1;
2515 }
2516
2517 p_cpo = save_cpo;
2518
2519#ifdef FEAT_WINDOWS
2520 qf_update_buffer();
2521#endif
2522
2523 /* Jump to first match. */
2524 if (qf_lists[qf_curlist].qf_count > 0)
2525 qf_jump(0, 0, FALSE);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002526 else
2527 EMSG2(_(e_nomatch2), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002528}
2529
2530#endif /* FEAT_QUICKFIX */