1/* 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 */ 29typedef struct qfline_S qfline_T; 30struct qfline_S 31{ 32 qfline_T *qf_next; /* pointer to next error in the list */ 33 qfline_T *qf_prev; /* pointer to previous error in the list */ 34 linenr_T qf_lnum; /* line number where the error occurred */ 35 int qf_fnum; /* file number for the line */ 36 int qf_col; /* column where the error occurred */ 37 int qf_nr; /* error number */ 38 char_u *qf_pattern; /* search pattern for the error */ 39 char_u *qf_text; /* description of the error */ 40 char_u qf_viscol; /* set to TRUE if qf_col is screen column */ 41 char_u qf_cleared; /* set to TRUE if line has been deleted */ 42 char_u qf_type; /* type of the error (mostly 'E'); 1 for 43 :helpgrep */ 44 char_u qf_valid; /* valid error message detected */ 45}; 46 47/* 48 * There is a stack of error lists. 49 */ 50#define LISTCOUNT 10 51 52typedef struct qf_list_S 53{ 54 qfline_T *qf_start; /* pointer to the first error */ 55 qfline_T *qf_ptr; /* pointer to the current error */ 56 int qf_count; /* number of errors (0 means no error list) */ 57 int qf_index; /* current index in the error list */ 58 int qf_nonevalid; /* TRUE if not a single valid entry found */ 59 char_u *qf_title; /* title derived from the command that created 60 * the error list */ 61} qf_list_T; 62 63struct qf_info_S 64{ 65 /* 66 * Count of references to this list. Used only for location lists. 67 * When a location list window reference this list, qf_refcount 68 * will be 2. Otherwise, qf_refcount will be 1. When qf_refcount 69 * reaches 0, the list is freed. 70 */ 71 int qf_refcount; 72 int qf_listcount; /* current number of lists */ 73 int qf_curlist; /* current error list */ 74 qf_list_T qf_lists[LISTCOUNT]; 75}; 76 77static qf_info_T ql_info; /* global quickfix list */ 78 79#define FMT_PATTERNS 10 /* maximum number of % recognized */ 80 81/* 82 * Structure used to hold the info of one part of 'errorformat' 83 */ 84typedef struct efm_S efm_T; 85struct efm_S 86{ 87 regprog_T *prog; /* pre-formatted part of 'errorformat' */ 88 efm_T *next; /* pointer to next (NULL if last) */ 89 char_u addr[FMT_PATTERNS]; /* indices of used % patterns */ 90 char_u prefix; /* prefix of this format line: */ 91 /* 'D' enter directory */ 92 /* 'X' leave directory */ 93 /* 'A' start of multi-line message */ 94 /* 'E' error message */ 95 /* 'W' warning message */ 96 /* 'I' informational message */ 97 /* 'C' continuation line */ 98 /* 'Z' end of multi-line message */ 99 /* 'G' general, unspecific message */ 100 /* 'P' push file (partial) message */ 101 /* 'Q' pop/quit file (partial) message */ 102 /* 'O' overread (partial) message */ 103 char_u flags; /* additional flags given in prefix */ 104 /* '-' do not include this line */ 105 /* '+' include whole line in message */ 106 int conthere; /* %> used */ 107}; 108 109static int qf_init_ext __ARGS((qf_info_T *qi, char_u *efile, buf_T *buf, typval_T *tv, char_u *errorformat, int newlist, linenr_T lnumfirst, linenr_T lnumlast, char_u *qf_title)); 110static void qf_new_list __ARGS((qf_info_T *qi, char_u *qf_title)); 111static void ll_free_all __ARGS((qf_info_T **pqi)); 112static int qf_add_entry __ARGS((qf_info_T *qi, qfline_T **prevp, char_u *dir, char_u *fname, int bufnum, char_u *mesg, long lnum, int col, int vis_col, char_u *pattern, int nr, int type, int valid)); 113static qf_info_T *ll_new_list __ARGS((void)); 114static void qf_msg __ARGS((qf_info_T *qi)); 115static void qf_free __ARGS((qf_info_T *qi, int idx)); 116static char_u *qf_types __ARGS((int, int)); 117static int qf_get_fnum __ARGS((char_u *, char_u *)); 118static char_u *qf_push_dir __ARGS((char_u *, struct dir_stack_T **)); 119static char_u *qf_pop_dir __ARGS((struct dir_stack_T **)); 120static char_u *qf_guess_filepath __ARGS((char_u *)); 121static void qf_fmt_text __ARGS((char_u *text, char_u *buf, int bufsize)); 122static void qf_clean_dir_stack __ARGS((struct dir_stack_T **)); 123#ifdef FEAT_WINDOWS 124static int qf_win_pos_update __ARGS((qf_info_T *qi, int old_qf_index)); 125static int is_qf_win __ARGS((win_T *win, qf_info_T *qi)); 126static win_T *qf_find_win __ARGS((qf_info_T *qi)); 127static buf_T *qf_find_buf __ARGS((qf_info_T *qi)); 128static void qf_update_buffer __ARGS((qf_info_T *qi)); 129static void qf_fill_buffer __ARGS((qf_info_T *qi)); 130#endif 131static char_u *get_mef_name __ARGS((void)); 132static buf_T *load_dummy_buffer __ARGS((char_u *fname)); 133static void wipe_dummy_buffer __ARGS((buf_T *buf)); 134static void unload_dummy_buffer __ARGS((buf_T *buf)); 135static qf_info_T *ll_get_or_alloc_list __ARGS((win_T *)); 136 137/* Quickfix window check helper macro */ 138#define IS_QF_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref == NULL) 139/* Location list window check helper macro */ 140#define IS_LL_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL) 141/* 142 * Return location list for window 'wp' 143 * For location list window, return the referenced location list 144 */ 145#define GET_LOC_LIST(wp) (IS_LL_WINDOW(wp) ? wp->w_llist_ref : wp->w_llist) 146 147/* 148 * Read the errorfile "efile" into memory, line by line, building the error 149 * list. Set the error list's title to qf_title. 150 * Return -1 for error, number of errors for success. 151 */ 152 int 153qf_init(wp, efile, errorformat, newlist, qf_title) 154 win_T *wp; 155 char_u *efile; 156 char_u *errorformat; 157 int newlist; /* TRUE: start a new error list */ 158 char_u *qf_title; 159{ 160 qf_info_T *qi = &ql_info; 161 162 if (efile == NULL) 163 return FAIL; 164 165 if (wp != NULL) 166 { 167 qi = ll_get_or_alloc_list(wp); 168 if (qi == NULL) 169 return FAIL; 170 } 171 172 return qf_init_ext(qi, efile, curbuf, NULL, errorformat, newlist, 173 (linenr_T)0, (linenr_T)0, 174 qf_title); 175} 176 177/* 178 * Read the errorfile "efile" into memory, line by line, building the error 179 * list. 180 * Alternative: when "efile" is null read errors from buffer "buf". 181 * Always use 'errorformat' from "buf" if there is a local value. 182 * Then "lnumfirst" and "lnumlast" specify the range of lines to use. 183 * Set the title of the list to "qf_title". 184 * Return -1 for error, number of errors for success. 185 */ 186 static int 187qf_init_ext(qi, efile, buf, tv, errorformat, newlist, lnumfirst, lnumlast, 188 qf_title) 189 qf_info_T *qi; 190 char_u *efile; 191 buf_T *buf; 192 typval_T *tv; 193 char_u *errorformat; 194 int newlist; /* TRUE: start a new error list */ 195 linenr_T lnumfirst; /* first line number to use */ 196 linenr_T lnumlast; /* last line number to use */ 197 char_u *qf_title; 198{ 199 char_u *namebuf; 200 char_u *errmsg; 201 char_u *pattern; 202 char_u *fmtstr = NULL; 203 int col = 0; 204 char_u use_viscol = FALSE; 205 int type = 0; 206 int valid; 207 linenr_T buflnum = lnumfirst; 208 long lnum = 0L; 209 int enr = 0; 210 FILE *fd = NULL; 211 qfline_T *qfprev = NULL; /* init to make SASC shut up */ 212 char_u *efmp; 213 efm_T *fmt_first = NULL; 214 efm_T *fmt_last = NULL; 215 efm_T *fmt_ptr; 216 efm_T *fmt_start = NULL; 217 char_u *efm; 218 char_u *ptr; 219 char_u *srcptr; 220 int len; 221 int i; 222 int round; 223 int idx = 0; 224 int multiline = FALSE; 225 int multiignore = FALSE; 226 int multiscan = FALSE; 227 int retval = -1; /* default: return error flag */ 228 char_u *directory = NULL; 229 char_u *currfile = NULL; 230 char_u *tail = NULL; 231 char_u *p_str = NULL; 232 listitem_T *p_li = NULL; 233 struct dir_stack_T *file_stack = NULL; 234 regmatch_T regmatch; 235 static struct fmtpattern 236 { 237 char_u convchar; 238 char *pattern; 239 } fmt_pat[FMT_PATTERNS] = 240 { 241 {'f', ".\\+"}, /* only used when at end */ 242 {'n', "\\d\\+"}, 243 {'l', "\\d\\+"}, 244 {'c', "\\d\\+"}, 245 {'t', "."}, 246 {'m', ".\\+"}, 247 {'r', ".*"}, 248 {'p', "[- .]*"}, 249 {'v', "\\d\\+"}, 250 {'s', ".\\+"} 251 }; 252 253 namebuf = alloc(CMDBUFFSIZE + 1); 254 errmsg = alloc(CMDBUFFSIZE + 1); 255 pattern = alloc(CMDBUFFSIZE + 1); 256 if (namebuf == NULL || errmsg == NULL || pattern == NULL) 257 goto qf_init_end; 258 259 if (efile != NULL && (fd = mch_fopen((char *)efile, "r")) == NULL) 260 { 261 EMSG2(_(e_openerrf), efile); 262 goto qf_init_end; 263 } 264 265 if (newlist || qi->qf_curlist == qi->qf_listcount) 266 /* make place for a new list */ 267 qf_new_list(qi, qf_title); 268 else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) 269 /* Adding to existing list, find last entry. */ 270 for (qfprev = qi->qf_lists[qi->qf_curlist].qf_start; 271 qfprev->qf_next != qfprev; qfprev = qfprev->qf_next) 272 ; 273 274/* 275 * Each part of the format string is copied and modified from errorformat to 276 * regex prog. Only a few % characters are allowed. 277 */ 278 /* Use the local value of 'errorformat' if it's set. */ 279 if (errorformat == p_efm && tv == NULL && *buf->b_p_efm != NUL) 280 efm = buf->b_p_efm; 281 else 282 efm = errorformat; 283 /* 284 * Get some space to modify the format string into. 285 */ 286 i = (FMT_PATTERNS * 3) + ((int)STRLEN(efm) << 2); 287 for (round = FMT_PATTERNS; round > 0; ) 288 i += (int)STRLEN(fmt_pat[--round].pattern); 289#ifdef COLON_IN_FILENAME 290 i += 12; /* "%f" can become twelve chars longer */ 291#else 292 i += 2; /* "%f" can become two chars longer */ 293#endif 294 if ((fmtstr = alloc(i)) == NULL) 295 goto error2; 296 297 while (efm[0] != NUL) 298 { 299 /* 300 * Allocate a new eformat structure and put it at the end of the list 301 */ 302 fmt_ptr = (efm_T *)alloc_clear((unsigned)sizeof(efm_T)); 303 if (fmt_ptr == NULL) 304 goto error2; 305 if (fmt_first == NULL) /* first one */ 306 fmt_first = fmt_ptr; 307 else 308 fmt_last->next = fmt_ptr; 309 fmt_last = fmt_ptr; 310 311 /* 312 * Isolate one part in the 'errorformat' option 313 */ 314 for (len = 0; efm[len] != NUL && efm[len] != ','; ++len) 315 if (efm[len] == '\\' && efm[len + 1] != NUL) 316 ++len; 317 318 /* 319 * Build regexp pattern from current 'errorformat' option 320 */ 321 ptr = fmtstr; 322 *ptr++ = '^'; 323 round = 0; 324 for (efmp = efm; efmp < efm + len; ++efmp) 325 { 326 if (*efmp == '%') 327 { 328 ++efmp; 329 for (idx = 0; idx < FMT_PATTERNS; ++idx) 330 if (fmt_pat[idx].convchar == *efmp) 331 break; 332 if (idx < FMT_PATTERNS) 333 { 334 if (fmt_ptr->addr[idx]) 335 { 336 sprintf((char *)errmsg, 337 _("E372: Too many %%%c in format string"), *efmp); 338 EMSG(errmsg); 339 goto error2; 340 } 341 if ((idx 342 && idx < 6 343 && vim_strchr((char_u *)"DXOPQ", 344 fmt_ptr->prefix) != NULL) 345 || (idx == 6 346 && vim_strchr((char_u *)"OPQ", 347 fmt_ptr->prefix) == NULL)) 348 { 349 sprintf((char *)errmsg, 350 _("E373: Unexpected %%%c in format string"), *efmp); 351 EMSG(errmsg); 352 goto error2; 353 } 354 fmt_ptr->addr[idx] = (char_u)++round; 355 *ptr++ = '\\'; 356 *ptr++ = '('; 357#ifdef BACKSLASH_IN_FILENAME 358 if (*efmp == 'f') 359 { 360 /* Also match "c:" in the file name, even when 361 * checking for a colon next: "%f:". 362 * "\%(\a:\)\=" */ 363 STRCPY(ptr, "\\%(\\a:\\)\\="); 364 ptr += 10; 365 } 366#endif 367 if (*efmp == 'f' && efmp[1] != NUL) 368 { 369 if (efmp[1] != '\\' && efmp[1] != '%') 370 { 371 /* A file name may contain spaces, but this isn't 372 * in "\f". For "%f:%l:%m" there may be a ":" in 373 * the file name. Use ".\{-1,}x" instead (x is 374 * the next character), the requirement that :999: 375 * follows should work. */ 376 STRCPY(ptr, ".\\{-1,}"); 377 ptr += 7; 378 } 379 else 380 { 381 /* File name followed by '\\' or '%': include as 382 * many file name chars as possible. */ 383 STRCPY(ptr, "\\f\\+"); 384 ptr += 4; 385 } 386 } 387 else 388 { 389 srcptr = (char_u *)fmt_pat[idx].pattern; 390 while ((*ptr = *srcptr++) != NUL) 391 ++ptr; 392 } 393 *ptr++ = '\\'; 394 *ptr++ = ')'; 395 } 396 else if (*efmp == '*') 397 { 398 if (*++efmp == '[' || *efmp == '\\') 399 { 400 if ((*ptr++ = *efmp) == '[') /* %*[^a-z0-9] etc. */ 401 { 402 if (efmp[1] == '^') 403 *ptr++ = *++efmp; 404 if (efmp < efm + len) 405 { 406 *ptr++ = *++efmp; /* could be ']' */ 407 while (efmp < efm + len 408 && (*ptr++ = *++efmp) != ']') 409 /* skip */; 410 if (efmp == efm + len) 411 { 412 EMSG(_("E374: Missing ] in format string")); 413 goto error2; 414 } 415 } 416 } 417 else if (efmp < efm + len) /* %*\D, %*\s etc. */ 418 *ptr++ = *++efmp; 419 *ptr++ = '\\'; 420 *ptr++ = '+'; 421 } 422 else 423 { 424 /* TODO: scanf()-like: %*ud, %*3c, %*f, ... ? */ 425 sprintf((char *)errmsg, 426 _("E375: Unsupported %%%c in format string"), *efmp); 427 EMSG(errmsg); 428 goto error2; 429 } 430 } 431 else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) 432 *ptr++ = *efmp; /* regexp magic characters */ 433 else if (*efmp == '#') 434 *ptr++ = '*'; 435 else if (*efmp == '>') 436 fmt_ptr->conthere = TRUE; 437 else if (efmp == efm + 1) /* analyse prefix */ 438 { 439 if (vim_strchr((char_u *)"+-", *efmp) != NULL) 440 fmt_ptr->flags = *efmp++; 441 if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) 442 fmt_ptr->prefix = *efmp; 443 else 444 { 445 sprintf((char *)errmsg, 446 _("E376: Invalid %%%c in format string prefix"), *efmp); 447 EMSG(errmsg); 448 goto error2; 449 } 450 } 451 else 452 { 453 sprintf((char *)errmsg, 454 _("E377: Invalid %%%c in format string"), *efmp); 455 EMSG(errmsg); 456 goto error2; 457 } 458 } 459 else /* copy normal character */ 460 { 461 if (*efmp == '\\' && efmp + 1 < efm + len) 462 ++efmp; 463 else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL) 464 *ptr++ = '\\'; /* escape regexp atoms */ 465 if (*efmp) 466 *ptr++ = *efmp; 467 } 468 } 469 *ptr++ = '$'; 470 *ptr = NUL; 471 if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL) 472 goto error2; 473 /* 474 * Advance to next part 475 */ 476 efm = skip_to_option_part(efm + len); /* skip comma and spaces */ 477 } 478 if (fmt_first == NULL) /* nothing found */ 479 { 480 EMSG(_("E378: 'errorformat' contains no pattern")); 481 goto error2; 482 } 483 484 /* 485 * got_int is reset here, because it was probably set when killing the 486 * ":make" command, but we still want to read the errorfile then. 487 */ 488 got_int = FALSE; 489 490 /* Always ignore case when looking for a matching error. */ 491 regmatch.rm_ic = TRUE; 492 493 if (tv != NULL) 494 { 495 if (tv->v_type == VAR_STRING) 496 p_str = tv->vval.v_string; 497 else if (tv->v_type == VAR_LIST) 498 p_li = tv->vval.v_list->lv_first; 499 } 500 501 /* 502 * Read the lines in the error file one by one. 503 * Try to recognize one of the error formats in each line. 504 */ 505 while (!got_int) 506 { 507 /* Get the next line. */ 508 if (fd == NULL) 509 { 510 if (tv != NULL) 511 { 512 if (tv->v_type == VAR_STRING) 513 { 514 /* Get the next line from the supplied string */ 515 char_u *p; 516 517 if (!*p_str) /* Reached the end of the string */ 518 break; 519 520 p = vim_strchr(p_str, '\n'); 521 if (p) 522 len = (int)(p - p_str + 1); 523 else 524 len = (int)STRLEN(p_str); 525 526 if (len > CMDBUFFSIZE - 2) 527 vim_strncpy(IObuff, p_str, CMDBUFFSIZE - 2); 528 else 529 vim_strncpy(IObuff, p_str, len); 530 531 p_str += len; 532 } 533 else if (tv->v_type == VAR_LIST) 534 { 535 /* Get the next line from the supplied list */ 536 while (p_li && p_li->li_tv.v_type != VAR_STRING) 537 p_li = p_li->li_next; /* Skip non-string items */ 538 539 if (!p_li) /* End of the list */ 540 break; 541 542 len = (int)STRLEN(p_li->li_tv.vval.v_string); 543 if (len > CMDBUFFSIZE - 2) 544 len = CMDBUFFSIZE - 2; 545 546 vim_strncpy(IObuff, p_li->li_tv.vval.v_string, len); 547 548 p_li = p_li->li_next; /* next item */ 549 } 550 } 551 else 552 { 553 /* Get the next line from the supplied buffer */ 554 if (buflnum > lnumlast) 555 break; 556 vim_strncpy(IObuff, ml_get_buf(buf, buflnum++, FALSE), 557 CMDBUFFSIZE - 2); 558 } 559 } 560 else if (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) == NULL) 561 break; 562 563 IObuff[CMDBUFFSIZE - 2] = NUL; /* for very long lines */ 564 if ((efmp = vim_strrchr(IObuff, '\n')) != NULL) 565 *efmp = NUL; 566#ifdef USE_CRNL 567 if ((efmp = vim_strrchr(IObuff, '\r')) != NULL) 568 *efmp = NUL; 569#endif 570 571 /* If there was no %> item start at the first pattern */ 572 if (fmt_start == NULL) 573 fmt_ptr = fmt_first; 574 else 575 { 576 fmt_ptr = fmt_start; 577 fmt_start = NULL; 578 } 579 580 /* 581 * Try to match each part of 'errorformat' until we find a complete 582 * match or no match. 583 */ 584 valid = TRUE; 585restofline: 586 for ( ; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) 587 { 588 idx = fmt_ptr->prefix; 589 if (multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) 590 continue; 591 namebuf[0] = NUL; 592 pattern[0] = NUL; 593 if (!multiscan) 594 errmsg[0] = NUL; 595 lnum = 0; 596 col = 0; 597 use_viscol = FALSE; 598 enr = -1; 599 type = 0; 600 tail = NULL; 601 602 regmatch.regprog = fmt_ptr->prog; 603 if (vim_regexec(®match, IObuff, (colnr_T)0)) 604 { 605 if ((idx == 'C' || idx == 'Z') && !multiline) 606 continue; 607 if (vim_strchr((char_u *)"EWI", idx) != NULL) 608 type = idx; 609 else 610 type = 0; 611 /* 612 * Extract error message data from matched line. 613 * We check for an actual submatch, because "\[" and "\]" in 614 * the 'errorformat' may cause the wrong submatch to be used. 615 */ 616 if ((i = (int)fmt_ptr->addr[0]) > 0) /* %f */ 617 { 618 int c; 619 620 if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) 621 continue; 622 623 /* Expand ~/file and $HOME/file to full path. */ 624 c = *regmatch.endp[i]; 625 *regmatch.endp[i] = NUL; 626 expand_env(regmatch.startp[i], namebuf, CMDBUFFSIZE); 627 *regmatch.endp[i] = c; 628 629 if (vim_strchr((char_u *)"OPQ", idx) != NULL 630 && mch_getperm(namebuf) == -1) 631 continue; 632 } 633 if ((i = (int)fmt_ptr->addr[1]) > 0) /* %n */ 634 { 635 if (regmatch.startp[i] == NULL) 636 continue; 637 enr = (int)atol((char *)regmatch.startp[i]); 638 } 639 if ((i = (int)fmt_ptr->addr[2]) > 0) /* %l */ 640 { 641 if (regmatch.startp[i] == NULL) 642 continue; 643 lnum = atol((char *)regmatch.startp[i]); 644 } 645 if ((i = (int)fmt_ptr->addr[3]) > 0) /* %c */ 646 { 647 if (regmatch.startp[i] == NULL) 648 continue; 649 col = (int)atol((char *)regmatch.startp[i]); 650 } 651 if ((i = (int)fmt_ptr->addr[4]) > 0) /* %t */ 652 { 653 if (regmatch.startp[i] == NULL) 654 continue; 655 type = *regmatch.startp[i]; 656 } 657 if (fmt_ptr->flags == '+' && !multiscan) /* %+ */ 658 STRCPY(errmsg, IObuff); 659 else if ((i = (int)fmt_ptr->addr[5]) > 0) /* %m */ 660 { 661 if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) 662 continue; 663 len = (int)(regmatch.endp[i] - regmatch.startp[i]); 664 vim_strncpy(errmsg, regmatch.startp[i], len); 665 } 666 if ((i = (int)fmt_ptr->addr[6]) > 0) /* %r */ 667 { 668 if (regmatch.startp[i] == NULL) 669 continue; 670 tail = regmatch.startp[i]; 671 } 672 if ((i = (int)fmt_ptr->addr[7]) > 0) /* %p */ 673 { 674 if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) 675 continue; 676 col = (int)(regmatch.endp[i] - regmatch.startp[i] + 1); 677 if (*((char_u *)regmatch.startp[i]) != TAB) 678 use_viscol = TRUE; 679 } 680 if ((i = (int)fmt_ptr->addr[8]) > 0) /* %v */ 681 { 682 if (regmatch.startp[i] == NULL) 683 continue; 684 col = (int)atol((char *)regmatch.startp[i]); 685 use_viscol = TRUE; 686 } 687 if ((i = (int)fmt_ptr->addr[9]) > 0) /* %s */ 688 { 689 if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) 690 continue; 691 len = (int)(regmatch.endp[i] - regmatch.startp[i]); 692 if (len > CMDBUFFSIZE - 5) 693 len = CMDBUFFSIZE - 5; 694 STRCPY(pattern, "^\\V"); 695 STRNCAT(pattern, regmatch.startp[i], len); 696 pattern[len + 3] = '\\'; 697 pattern[len + 4] = '$'; 698 pattern[len + 5] = NUL; 699 } 700 break; 701 } 702 } 703 multiscan = FALSE; 704 705 if (fmt_ptr == NULL || idx == 'D' || idx == 'X') 706 { 707 if (fmt_ptr != NULL) 708 { 709 if (idx == 'D') /* enter directory */ 710 { 711 if (*namebuf == NUL) 712 { 713 EMSG(_("E379: Missing or empty directory name")); 714 goto error2; 715 } 716 if ((directory = qf_push_dir(namebuf, &dir_stack)) == NULL) 717 goto error2; 718 } 719 else if (idx == 'X') /* leave directory */ 720 directory = qf_pop_dir(&dir_stack); 721 } 722 namebuf[0] = NUL; /* no match found, remove file name */ 723 lnum = 0; /* don't jump to this line */ 724 valid = FALSE; 725 STRCPY(errmsg, IObuff); /* copy whole line to error message */ 726 if (fmt_ptr == NULL) 727 multiline = multiignore = FALSE; 728 } 729 else if (fmt_ptr != NULL) 730 { 731 /* honor %> item */ 732 if (fmt_ptr->conthere) 733 fmt_start = fmt_ptr; 734 735 if (vim_strchr((char_u *)"AEWI", idx) != NULL) 736 multiline = TRUE; /* start of a multi-line message */ 737 else if (vim_strchr((char_u *)"CZ", idx) != NULL) 738 { /* continuation of multi-line msg */ 739 if (qfprev == NULL) 740 goto error2; 741 if (*errmsg && !multiignore) 742 { 743 len = (int)STRLEN(qfprev->qf_text); 744 if ((ptr = alloc((unsigned)(len + STRLEN(errmsg) + 2))) 745 == NULL) 746 goto error2; 747 STRCPY(ptr, qfprev->qf_text); 748 vim_free(qfprev->qf_text); 749 qfprev->qf_text = ptr; 750 *(ptr += len) = '\n'; 751 STRCPY(++ptr, errmsg); 752 } 753 if (qfprev->qf_nr == -1) 754 qfprev->qf_nr = enr; 755 if (vim_isprintc(type) && !qfprev->qf_type) 756 qfprev->qf_type = type; /* only printable chars allowed */ 757 if (!qfprev->qf_lnum) 758 qfprev->qf_lnum = lnum; 759 if (!qfprev->qf_col) 760 qfprev->qf_col = col; 761 qfprev->qf_viscol = use_viscol; 762 if (!qfprev->qf_fnum) 763 qfprev->qf_fnum = qf_get_fnum(directory, 764 *namebuf || directory ? namebuf 765 : currfile && valid ? currfile : 0); 766 if (idx == 'Z') 767 multiline = multiignore = FALSE; 768 line_breakcheck(); 769 continue; 770 } 771 else if (vim_strchr((char_u *)"OPQ", idx) != NULL) 772 { 773 /* global file names */ 774 valid = FALSE; 775 if (*namebuf == NUL || mch_getperm(namebuf) >= 0) 776 { 777 if (*namebuf && idx == 'P') 778 currfile = qf_push_dir(namebuf, &file_stack); 779 else if (idx == 'Q') 780 currfile = qf_pop_dir(&file_stack); 781 *namebuf = NUL; 782 if (tail && *tail) 783 { 784 STRMOVE(IObuff, skipwhite(tail)); 785 multiscan = TRUE; 786 goto restofline; 787 } 788 } 789 } 790 if (fmt_ptr->flags == '-') /* generally exclude this line */ 791 { 792 if (multiline) 793 multiignore = TRUE; /* also exclude continuation lines */ 794 continue; 795 } 796 } 797 798 if (qf_add_entry(qi, &qfprev, 799 directory, 800 (*namebuf || directory) 801 ? namebuf 802 : ((currfile && valid) ? currfile : (char_u *)NULL), 803 0, 804 errmsg, 805 lnum, 806 col, 807 use_viscol, 808 pattern, 809 enr, 810 type, 811 valid) == FAIL) 812 goto error2; 813 line_breakcheck(); 814 } 815 if (fd == NULL || !ferror(fd)) 816 { 817 if (qi->qf_lists[qi->qf_curlist].qf_index == 0) 818 { 819 /* no valid entry found */ 820 qi->qf_lists[qi->qf_curlist].qf_ptr = 821 qi->qf_lists[qi->qf_curlist].qf_start; 822 qi->qf_lists[qi->qf_curlist].qf_index = 1; 823 qi->qf_lists[qi->qf_curlist].qf_nonevalid = TRUE; 824 } 825 else 826 { 827 qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE; 828 if (qi->qf_lists[qi->qf_curlist].qf_ptr == NULL) 829 qi->qf_lists[qi->qf_curlist].qf_ptr = 830 qi->qf_lists[qi->qf_curlist].qf_start; 831 } 832 /* return number of matches */ 833 retval = qi->qf_lists[qi->qf_curlist].qf_count; 834 goto qf_init_ok; 835 } 836 EMSG(_(e_readerrf)); 837error2: 838 qf_free(qi, qi->qf_curlist); 839 qi->qf_listcount--; 840 if (qi->qf_curlist > 0) 841 --qi->qf_curlist; 842qf_init_ok: 843 if (fd != NULL) 844 fclose(fd); 845 for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first) 846 { 847 fmt_first = fmt_ptr->next; 848 vim_free(fmt_ptr->prog); 849 vim_free(fmt_ptr); 850 } 851 qf_clean_dir_stack(&dir_stack); 852 qf_clean_dir_stack(&file_stack); 853qf_init_end: 854 vim_free(namebuf); 855 vim_free(errmsg); 856 vim_free(pattern); 857 vim_free(fmtstr); 858 859#ifdef FEAT_WINDOWS 860 qf_update_buffer(qi); 861#endif 862 863 return retval; 864} 865 866/* 867 * Prepare for adding a new quickfix list. 868 */ 869 static void 870qf_new_list(qi, qf_title) 871 qf_info_T *qi; 872 char_u *qf_title; 873{ 874 int i; 875 876 /* 877 * If the current entry is not the last entry, delete entries below 878 * the current entry. This makes it possible to browse in a tree-like 879 * way with ":grep'. 880 */ 881 while (qi->qf_listcount > qi->qf_curlist + 1) 882 qf_free(qi, --qi->qf_listcount); 883 884 /* 885 * When the stack is full, remove to oldest entry 886 * Otherwise, add a new entry. 887 */ 888 if (qi->qf_listcount == LISTCOUNT) 889 { 890 qf_free(qi, 0); 891 for (i = 1; i < LISTCOUNT; ++i) 892 qi->qf_lists[i - 1] = qi->qf_lists[i]; 893 qi->qf_curlist = LISTCOUNT - 1; 894 } 895 else 896 qi->qf_curlist = qi->qf_listcount++; 897 qi->qf_lists[qi->qf_curlist].qf_index = 0; 898 qi->qf_lists[qi->qf_curlist].qf_count = 0; 899 if (qf_title != NULL) 900 { 901 char_u *p = alloc((int)STRLEN(qf_title) + 2); 902 903 qi->qf_lists[qi->qf_curlist].qf_title = p; 904 if (p != NULL) 905 sprintf((char *)p, ":%s", (char *)qf_title); 906 } 907 else 908 qi->qf_lists[qi->qf_curlist].qf_title = NULL; 909} 910 911/* 912 * Free a location list 913 */ 914 static void 915ll_free_all(pqi) 916 qf_info_T **pqi; 917{ 918 int i; 919 qf_info_T *qi; 920 921 qi = *pqi; 922 if (qi == NULL) 923 return; 924 *pqi = NULL; /* Remove reference to this list */ 925 926 qi->qf_refcount--; 927 if (qi->qf_refcount < 1) 928 { 929 /* No references to this location list */ 930 for (i = 0; i < qi->qf_listcount; ++i) 931 qf_free(qi, i); 932 vim_free(qi); 933 } 934} 935 936 void 937qf_free_all(wp) 938 win_T *wp; 939{ 940 int i; 941 qf_info_T *qi = &ql_info; 942 943 if (wp != NULL) 944 { 945 /* location list */ 946 ll_free_all(&wp->w_llist); 947 ll_free_all(&wp->w_llist_ref); 948 } 949 else 950 /* quickfix list */ 951 for (i = 0; i < qi->qf_listcount; ++i) 952 qf_free(qi, i); 953} 954 955/* 956 * Add an entry to the end of the list of errors. 957 * Returns OK or FAIL. 958 */ 959 static int 960qf_add_entry(qi, prevp, dir, fname, bufnum, mesg, lnum, col, vis_col, pattern, 961 nr, type, valid) 962 qf_info_T *qi; /* quickfix list */ 963 qfline_T **prevp; /* pointer to previously added entry or NULL */ 964 char_u *dir; /* optional directory name */ 965 char_u *fname; /* file name or NULL */ 966 int bufnum; /* buffer number or zero */ 967 char_u *mesg; /* message */ 968 long lnum; /* line number */ 969 int col; /* column */ 970 int vis_col; /* using visual column */ 971 char_u *pattern; /* search pattern */ 972 int nr; /* error number */ 973 int type; /* type character */ 974 int valid; /* valid entry */ 975{ 976 qfline_T *qfp; 977 978 if ((qfp = (qfline_T *)alloc((unsigned)sizeof(qfline_T))) == NULL) 979 return FAIL; 980 if (bufnum != 0) 981 qfp->qf_fnum = bufnum; 982 else 983 qfp->qf_fnum = qf_get_fnum(dir, fname); 984 if ((qfp->qf_text = vim_strsave(mesg)) == NULL) 985 { 986 vim_free(qfp); 987 return FAIL; 988 } 989 qfp->qf_lnum = lnum; 990 qfp->qf_col = col; 991 qfp->qf_viscol = vis_col; 992 if (pattern == NULL || *pattern == NUL) 993 qfp->qf_pattern = NULL; 994 else if ((qfp->qf_pattern = vim_strsave(pattern)) == NULL) 995 { 996 vim_free(qfp->qf_text); 997 vim_free(qfp); 998 return FAIL; 999 } 1000 qfp->qf_nr = nr; 1001 if (type != 1 && !vim_isprintc(type)) /* only printable chars allowed */ 1002 type = 0; 1003 qfp->qf_type = type; 1004 qfp->qf_valid = valid; 1005 1006 if (qi->qf_lists[qi->qf_curlist].qf_count == 0) 1007 /* first element in the list */ 1008 { 1009 qi->qf_lists[qi->qf_curlist].qf_start = qfp; 1010 qfp->qf_prev = qfp; /* first element points to itself */ 1011 } 1012 else 1013 { 1014 qfp->qf_prev = *prevp; 1015 (*prevp)->qf_next = qfp; 1016 } 1017 qfp->qf_next = qfp; /* last element points to itself */ 1018 qfp->qf_cleared = FALSE; 1019 *prevp = qfp; 1020 ++qi->qf_lists[qi->qf_curlist].qf_count; 1021 if (qi->qf_lists[qi->qf_curlist].qf_index == 0 && qfp->qf_valid) 1022 /* first valid entry */ 1023 { 1024 qi->qf_lists[qi->qf_curlist].qf_index = 1025 qi->qf_lists[qi->qf_curlist].qf_count; 1026 qi->qf_lists[qi->qf_curlist].qf_ptr = qfp; 1027 } 1028 1029 return OK; 1030} 1031 1032/* 1033 * Allocate a new location list 1034 */ 1035 static qf_info_T * 1036ll_new_list() 1037{ 1038 qf_info_T *qi; 1039 1040 qi = (qf_info_T *)alloc((unsigned)sizeof(qf_info_T)); 1041 if (qi != NULL) 1042 { 1043 vim_memset(qi, 0, (size_t)(sizeof(qf_info_T))); 1044 qi->qf_refcount++; 1045 } 1046 1047 return qi; 1048} 1049 1050/* 1051 * Return the location list for window 'wp'. 1052 * If not present, allocate a location list 1053 */ 1054 static qf_info_T * 1055ll_get_or_alloc_list(wp) 1056 win_T *wp; 1057{ 1058 if (IS_LL_WINDOW(wp)) 1059 /* For a location list window, use the referenced location list */ 1060 return wp->w_llist_ref; 1061 1062 /* 1063 * For a non-location list window, w_llist_ref should not point to a 1064 * location list. 1065 */ 1066 ll_free_all(&wp->w_llist_ref); 1067 1068 if (wp->w_llist == NULL) 1069 wp->w_llist = ll_new_list(); /* new location list */ 1070 return wp->w_llist; 1071} 1072 1073/* 1074 * Copy the location list from window "from" to window "to". 1075 */ 1076 void 1077copy_loclist(from, to) 1078 win_T *from; 1079 win_T *to; 1080{ 1081 qf_info_T *qi; 1082 int idx; 1083 int i; 1084 1085 /* 1086 * When copying from a location list window, copy the referenced 1087 * location list. For other windows, copy the location list for 1088 * that window. 1089 */ 1090 if (IS_LL_WINDOW(from)) 1091 qi = from->w_llist_ref; 1092 else 1093 qi = from->w_llist; 1094 1095 if (qi == NULL) /* no location list to copy */ 1096 return; 1097 1098 /* allocate a new location list */ 1099 if ((to->w_llist = ll_new_list()) == NULL) 1100 return; 1101 1102 to->w_llist->qf_listcount = qi->qf_listcount; 1103 1104 /* Copy the location lists one at a time */ 1105 for (idx = 0; idx < qi->qf_listcount; idx++) 1106 { 1107 qf_list_T *from_qfl; 1108 qf_list_T *to_qfl; 1109 1110 to->w_llist->qf_curlist = idx; 1111 1112 from_qfl = &qi->qf_lists[idx]; 1113 to_qfl = &to->w_llist->qf_lists[idx]; 1114 1115 /* Some of the fields are populated by qf_add_entry() */ 1116 to_qfl->qf_nonevalid = from_qfl->qf_nonevalid; 1117 to_qfl->qf_count = 0; 1118 to_qfl->qf_index = 0; 1119 to_qfl->qf_start = NULL; 1120 to_qfl->qf_ptr = NULL; 1121 if (from_qfl->qf_title != NULL) 1122 to_qfl->qf_title = vim_strsave(from_qfl->qf_title); 1123 else 1124 to_qfl->qf_title = NULL; 1125 1126 if (from_qfl->qf_count) 1127 { 1128 qfline_T *from_qfp; 1129 qfline_T *prevp = NULL; 1130 1131 /* copy all the location entries in this list */ 1132 for (i = 0, from_qfp = from_qfl->qf_start; i < from_qfl->qf_count; 1133 ++i, from_qfp = from_qfp->qf_next) 1134 { 1135 if (qf_add_entry(to->w_llist, &prevp, 1136 NULL, 1137 NULL, 1138 0, 1139 from_qfp->qf_text, 1140 from_qfp->qf_lnum, 1141 from_qfp->qf_col, 1142 from_qfp->qf_viscol, 1143 from_qfp->qf_pattern, 1144 from_qfp->qf_nr, 1145 0, 1146 from_qfp->qf_valid) == FAIL) 1147 { 1148 qf_free_all(to); 1149 return; 1150 } 1151 /* 1152 * qf_add_entry() will not set the qf_num field, as the 1153 * directory and file names are not supplied. So the qf_fnum 1154 * field is copied here. 1155 */ 1156 prevp->qf_fnum = from_qfp->qf_fnum; /* file number */ 1157 prevp->qf_type = from_qfp->qf_type; /* error type */ 1158 if (from_qfl->qf_ptr == from_qfp) 1159 to_qfl->qf_ptr = prevp; /* current location */ 1160 } 1161 } 1162 1163 to_qfl->qf_index = from_qfl->qf_index; /* current index in the list */ 1164 1165 /* When no valid entries are present in the list, qf_ptr points to 1166 * the first item in the list */ 1167 if (to_qfl->qf_nonevalid == TRUE) 1168 to_qfl->qf_ptr = to_qfl->qf_start; 1169 } 1170 1171 to->w_llist->qf_curlist = qi->qf_curlist; /* current list */ 1172} 1173 1174/* 1175 * get buffer number for file "dir.name" 1176 */ 1177 static int 1178qf_get_fnum(directory, fname) 1179 char_u *directory; 1180 char_u *fname; 1181{ 1182 if (fname == NULL || *fname == NUL) /* no file name */ 1183 return 0; 1184 { 1185#ifdef RISCOS 1186 /* Name is reported as `main.c', but file is `c.main' */ 1187 return ro_buflist_add(fname); 1188#else 1189 char_u *ptr; 1190 int fnum; 1191 1192# ifdef VMS 1193 vms_remove_version(fname); 1194# endif 1195# ifdef BACKSLASH_IN_FILENAME 1196 if (directory != NULL) 1197 slash_adjust(directory); 1198 slash_adjust(fname); 1199# endif 1200 if (directory != NULL && !vim_isAbsName(fname) 1201 && (ptr = concat_fnames(directory, fname, TRUE)) != NULL) 1202 { 1203 /* 1204 * Here we check if the file really exists. 1205 * This should normally be true, but if make works without 1206 * "leaving directory"-messages we might have missed a 1207 * directory change. 1208 */ 1209 if (mch_getperm(ptr) < 0) 1210 { 1211 vim_free(ptr); 1212 directory = qf_guess_filepath(fname); 1213 if (directory) 1214 ptr = concat_fnames(directory, fname, TRUE); 1215 else 1216 ptr = vim_strsave(fname); 1217 } 1218 /* Use concatenated directory name and file name */ 1219 fnum = buflist_add(ptr, 0); 1220 vim_free(ptr); 1221 return fnum; 1222 } 1223 return buflist_add(fname, 0); 1224#endif 1225 } 1226} 1227 1228/* 1229 * push dirbuf onto the directory stack and return pointer to actual dir or 1230 * NULL on error 1231 */ 1232 static char_u * 1233qf_push_dir(dirbuf, stackptr) 1234 char_u *dirbuf; 1235 struct dir_stack_T **stackptr; 1236{ 1237 struct dir_stack_T *ds_new; 1238 struct dir_stack_T *ds_ptr; 1239 1240 /* allocate new stack element and hook it in */ 1241 ds_new = (struct dir_stack_T *)alloc((unsigned)sizeof(struct dir_stack_T)); 1242 if (ds_new == NULL) 1243 return NULL; 1244 1245 ds_new->next = *stackptr; 1246 *stackptr = ds_new; 1247 1248 /* store directory on the stack */ 1249 if (vim_isAbsName(dirbuf) 1250 || (*stackptr)->next == NULL 1251 || (*stackptr && dir_stack != *stackptr)) 1252 (*stackptr)->dirname = vim_strsave(dirbuf); 1253 else 1254 { 1255 /* Okay we don't have an absolute path. 1256 * dirbuf must be a subdir of one of the directories on the stack. 1257 * Let's search... 1258 */ 1259 ds_new = (*stackptr)->next; 1260 (*stackptr)->dirname = NULL; 1261 while (ds_new) 1262 { 1263 vim_free((*stackptr)->dirname); 1264 (*stackptr)->dirname = concat_fnames(ds_new->dirname, dirbuf, 1265 TRUE); 1266 if (mch_isdir((*stackptr)->dirname) == TRUE) 1267 break; 1268 1269 ds_new = ds_new->next; 1270 } 1271 1272 /* clean up all dirs we already left */ 1273 while ((*stackptr)->next != ds_new) 1274 { 1275 ds_ptr = (*stackptr)->next; 1276 (*stackptr)->next = (*stackptr)->next->next; 1277 vim_free(ds_ptr->dirname); 1278 vim_free(ds_ptr); 1279 } 1280 1281 /* Nothing found -> it must be on top level */ 1282 if (ds_new == NULL) 1283 { 1284 vim_free((*stackptr)->dirname); 1285 (*stackptr)->dirname = vim_strsave(dirbuf); 1286 } 1287 } 1288 1289 if ((*stackptr)->dirname != NULL) 1290 return (*stackptr)->dirname; 1291 else 1292 { 1293 ds_ptr = *stackptr; 1294 *stackptr = (*stackptr)->next; 1295 vim_free(ds_ptr); 1296 return NULL; 1297 } 1298} 1299 1300 1301/* 1302 * pop dirbuf from the directory stack and return previous directory or NULL if 1303 * stack is empty 1304 */ 1305 static char_u * 1306qf_pop_dir(stackptr) 1307 struct dir_stack_T **stackptr; 1308{ 1309 struct dir_stack_T *ds_ptr; 1310 1311 /* TODO: Should we check if dirbuf is the directory on top of the stack? 1312 * What to do if it isn't? */ 1313 1314 /* pop top element and free it */ 1315 if (*stackptr != NULL) 1316 { 1317 ds_ptr = *stackptr; 1318 *stackptr = (*stackptr)->next; 1319 vim_free(ds_ptr->dirname); 1320 vim_free(ds_ptr); 1321 } 1322 1323 /* return NEW top element as current dir or NULL if stack is empty*/ 1324 return *stackptr ? (*stackptr)->dirname : NULL; 1325} 1326 1327/* 1328 * clean up directory stack 1329 */ 1330 static void 1331qf_clean_dir_stack(stackptr) 1332 struct dir_stack_T **stackptr; 1333{ 1334 struct dir_stack_T *ds_ptr; 1335 1336 while ((ds_ptr = *stackptr) != NULL) 1337 { 1338 *stackptr = (*stackptr)->next; 1339 vim_free(ds_ptr->dirname); 1340 vim_free(ds_ptr); 1341 } 1342} 1343 1344/* 1345 * Check in which directory of the directory stack the given file can be 1346 * found. 1347 * Returns a pointer to the directory name or NULL if not found 1348 * Cleans up intermediate directory entries. 1349 * 1350 * TODO: How to solve the following problem? 1351 * If we have the this directory tree: 1352 * ./ 1353 * ./aa 1354 * ./aa/bb 1355 * ./bb 1356 * ./bb/x.c 1357 * and make says: 1358 * making all in aa 1359 * making all in bb 1360 * x.c:9: Error 1361 * Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb. 1362 * qf_guess_filepath will return NULL. 1363 */ 1364 static char_u * 1365qf_guess_filepath(filename) 1366 char_u *filename; 1367{ 1368 struct dir_stack_T *ds_ptr; 1369 struct dir_stack_T *ds_tmp; 1370 char_u *fullname; 1371 1372 /* no dirs on the stack - there's nothing we can do */ 1373 if (dir_stack == NULL) 1374 return NULL; 1375 1376 ds_ptr = dir_stack->next; 1377 fullname = NULL; 1378 while (ds_ptr) 1379 { 1380 vim_free(fullname); 1381 fullname = concat_fnames(ds_ptr->dirname, filename, TRUE); 1382 1383 /* If concat_fnames failed, just go on. The worst thing that can happen 1384 * is that we delete the entire stack. 1385 */ 1386 if ((fullname != NULL) && (mch_getperm(fullname) >= 0)) 1387 break; 1388 1389 ds_ptr = ds_ptr->next; 1390 } 1391 1392 vim_free(fullname); 1393 1394 /* clean up all dirs we already left */ 1395 while (dir_stack->next != ds_ptr) 1396 { 1397 ds_tmp = dir_stack->next; 1398 dir_stack->next = dir_stack->next->next; 1399 vim_free(ds_tmp->dirname); 1400 vim_free(ds_tmp); 1401 } 1402 1403 return ds_ptr==NULL? NULL: ds_ptr->dirname; 1404 1405} 1406 1407/* 1408 * jump to a quickfix line 1409 * if dir == FORWARD go "errornr" valid entries forward 1410 * if dir == BACKWARD go "errornr" valid entries backward 1411 * if dir == FORWARD_FILE go "errornr" valid entries files backward 1412 * if dir == BACKWARD_FILE go "errornr" valid entries files backward 1413 * else if "errornr" is zero, redisplay the same line 1414 * else go to entry "errornr" 1415 */ 1416 void 1417qf_jump(qi, dir, errornr, forceit) 1418 qf_info_T *qi; 1419 int dir; 1420 int errornr; 1421 int forceit; 1422{ 1423 qf_info_T *ll_ref; 1424 qfline_T *qf_ptr; 1425 qfline_T *old_qf_ptr; 1426 int qf_index; 1427 int old_qf_fnum; 1428 int old_qf_index; 1429 int prev_index; 1430 static char_u *e_no_more_items = (char_u *)N_("E553: No more items"); 1431 char_u *err = e_no_more_items; 1432 linenr_T i; 1433 buf_T *old_curbuf; 1434 linenr_T old_lnum; 1435 colnr_T screen_col; 1436 colnr_T char_col; 1437 char_u *line; 1438#ifdef FEAT_WINDOWS 1439 char_u *old_swb = p_swb; 1440 unsigned old_swb_flags = swb_flags; 1441 int opened_window = FALSE; 1442 win_T *win; 1443 win_T *altwin; 1444 int flags; 1445#endif 1446 win_T *oldwin = curwin; 1447 int print_message = TRUE; 1448 int len; 1449#ifdef FEAT_FOLDING 1450 int old_KeyTyped = KeyTyped; /* getting file may reset it */ 1451#endif 1452 int ok = OK; 1453 int usable_win; 1454 1455 if (qi == NULL) 1456 qi = &ql_info; 1457 1458 if (qi->qf_curlist >= qi->qf_listcount 1459 || qi->qf_lists[qi->qf_curlist].qf_count == 0) 1460 { 1461 EMSG(_(e_quickfix)); 1462 return; 1463 } 1464 1465 qf_ptr = qi->qf_lists[qi->qf_curlist].qf_ptr; 1466 old_qf_ptr = qf_ptr; 1467 qf_index = qi->qf_lists[qi->qf_curlist].qf_index; 1468 old_qf_index = qf_index; 1469 if (dir == FORWARD || dir == FORWARD_FILE) /* next valid entry */ 1470 { 1471 while (errornr--) 1472 { 1473 old_qf_ptr = qf_ptr; 1474 prev_index = qf_index; 1475 old_qf_fnum = qf_ptr->qf_fnum; 1476 do 1477 { 1478 if (qf_index == qi->qf_lists[qi->qf_curlist].qf_count 1479 || qf_ptr->qf_next == NULL) 1480 { 1481 qf_ptr = old_qf_ptr; 1482 qf_index = prev_index; 1483 if (err != NULL) 1484 { 1485 EMSG(_(err)); 1486 goto theend; 1487 } 1488 errornr = 0; 1489 break; 1490 } 1491 ++qf_index; 1492 qf_ptr = qf_ptr->qf_next; 1493 } while ((!qi->qf_lists[qi->qf_curlist].qf_nonevalid 1494 && !qf_ptr->qf_valid) 1495 || (dir == FORWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum)); 1496 err = NULL; 1497 } 1498 } 1499 else if (dir == BACKWARD || dir == BACKWARD_FILE) /* prev. valid entry */ 1500 { 1501 while (errornr--) 1502 { 1503 old_qf_ptr = qf_ptr; 1504 prev_index = qf_index; 1505 old_qf_fnum = qf_ptr->qf_fnum; 1506 do 1507 { 1508 if (qf_index == 1 || qf_ptr->qf_prev == NULL) 1509 { 1510 qf_ptr = old_qf_ptr; 1511 qf_index = prev_index; 1512 if (err != NULL) 1513 { 1514 EMSG(_(err)); 1515 goto theend; 1516 } 1517 errornr = 0; 1518 break; 1519 } 1520 --qf_index; 1521 qf_ptr = qf_ptr->qf_prev; 1522 } while ((!qi->qf_lists[qi->qf_curlist].qf_nonevalid 1523 && !qf_ptr->qf_valid) 1524 || (dir == BACKWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum)); 1525 err = NULL; 1526 } 1527 } 1528 else if (errornr != 0) /* go to specified number */ 1529 { 1530 while (errornr < qf_index && qf_index > 1 && qf_ptr->qf_prev != NULL) 1531 { 1532 --qf_index; 1533 qf_ptr = qf_ptr->qf_prev; 1534 } 1535 while (errornr > qf_index && qf_index < 1536 qi->qf_lists[qi->qf_curlist].qf_count 1537 && qf_ptr->qf_next != NULL) 1538 { 1539 ++qf_index; 1540 qf_ptr = qf_ptr->qf_next; 1541 } 1542 } 1543 1544#ifdef FEAT_WINDOWS 1545 qi->qf_lists[qi->qf_curlist].qf_index = qf_index; 1546 if (qf_win_pos_update(qi, old_qf_index)) 1547 /* No need to print the error message if it's visible in the error 1548 * window */ 1549 print_message = FALSE; 1550 1551 /* 1552 * For ":helpgrep" find a help window or open one. 1553 */ 1554 if (qf_ptr->qf_type == 1 && (!curwin->w_buffer->b_help || cmdmod.tab != 0)) 1555 { 1556 win_T *wp; 1557 1558 if (cmdmod.tab != 0) 1559 wp = NULL; 1560 else 1561 for (wp = firstwin; wp != NULL; wp = wp->w_next) 1562 if (wp->w_buffer != NULL && wp->w_buffer->b_help) 1563 break; 1564 if (wp != NULL && wp->w_buffer->b_nwindows > 0) 1565 win_enter(wp, TRUE); 1566 else 1567 { 1568 /* 1569 * Split off help window; put it at far top if no position 1570 * specified, the current window is vertically split and narrow. 1571 */ 1572 flags = WSP_HELP; 1573# ifdef FEAT_VERTSPLIT 1574 if (cmdmod.split == 0 && curwin->w_width != Columns 1575 && curwin->w_width < 80) 1576 flags |= WSP_TOP; 1577# endif 1578 if (qi != &ql_info) 1579 flags |= WSP_NEWLOC; /* don't copy the location list */ 1580 1581 if (win_split(0, flags) == FAIL) 1582 goto theend; 1583 opened_window = TRUE; /* close it when fail */ 1584 1585 if (curwin->w_height < p_hh) 1586 win_setheight((int)p_hh); 1587 1588 if (qi != &ql_info) /* not a quickfix list */ 1589 { 1590 /* The new window should use the supplied location list */ 1591 curwin->w_llist = qi; 1592 qi->qf_refcount++; 1593 } 1594 } 1595 1596 if (!p_im) 1597 restart_edit = 0; /* don't want insert mode in help file */ 1598 } 1599 1600 /* 1601 * If currently in the quickfix window, find another window to show the 1602 * file in. 1603 */ 1604 if (bt_quickfix(curbuf) && !opened_window) 1605 { 1606 /* 1607 * If there is no file specified, we don't know where to go. 1608 * But do advance, otherwise ":cn" gets stuck. 1609 */ 1610 if (qf_ptr->qf_fnum == 0) 1611 goto theend; 1612 1613 /* Locate a window showing a normal buffer */ 1614 usable_win = 0; 1615 FOR_ALL_WINDOWS(win) 1616 if (win->w_buffer->b_p_bt[0] == NUL) 1617 { 1618 usable_win = 1; 1619 break; 1620 } 1621 1622 /* 1623 * If no usable window is found and 'switchbuf' contains "usetab" 1624 * then search in other tabs. 1625 */ 1626 if (!usable_win && (swb_flags & SWB_USETAB)) 1627 { 1628 tabpage_T *tp; 1629 win_T *wp; 1630 1631 FOR_ALL_TAB_WINDOWS(tp, wp) 1632 { 1633 if (wp->w_buffer->b_fnum == qf_ptr->qf_fnum) 1634 { 1635 goto_tabpage_win(tp, wp); 1636 usable_win = 1; 1637 goto win_found; 1638 } 1639 } 1640 } 1641win_found: 1642 1643 /* 1644 * If there is only one window and it is the quickfix window, create a 1645 * new one above the quickfix window. 1646 */ 1647 if (((firstwin == lastwin) && bt_quickfix(curbuf)) || !usable_win) 1648 { 1649 ll_ref = curwin->w_llist_ref; 1650 1651 flags = WSP_ABOVE; 1652 if (ll_ref != NULL) 1653 flags |= WSP_NEWLOC; 1654 if (win_split(0, flags) == FAIL) 1655 goto failed; /* not enough room for window */ 1656 opened_window = TRUE; /* close it when fail */ 1657 p_swb = empty_option; /* don't split again */ 1658 swb_flags = 0; 1659# ifdef FEAT_SCROLLBIND 1660 curwin->w_p_scb = FALSE; 1661# endif 1662 if (ll_ref != NULL) 1663 { 1664 /* The new window should use the location list from the 1665 * location list window */ 1666 curwin->w_llist = ll_ref; 1667 ll_ref->qf_refcount++; 1668 } 1669 } 1670 else 1671 { 1672 if (curwin->w_llist_ref != NULL) 1673 { 1674 /* In a location window */ 1675 ll_ref = curwin->w_llist_ref; 1676 1677 /* Find the window with the same location list */ 1678 FOR_ALL_WINDOWS(win) 1679 if (win->w_llist == ll_ref) 1680 break; 1681 if (win == NULL) 1682 { 1683 /* Find the window showing the selected file */ 1684 FOR_ALL_WINDOWS(win) 1685 if (win->w_buffer->b_fnum == qf_ptr->qf_fnum) 1686 break; 1687 if (win == NULL) 1688 { 1689 /* Find a previous usable window */ 1690 win = curwin; 1691 do 1692 { 1693 if (win->w_buffer->b_p_bt[0] == NUL) 1694 break; 1695 if (win->w_prev == NULL) 1696 win = lastwin; /* wrap around the top */ 1697 else 1698 win = win->w_prev; /* go to previous window */ 1699 } while (win != curwin); 1700 } 1701 } 1702 win_goto(win); 1703 1704 /* If the location list for the window is not set, then set it 1705 * to the location list from the location window */ 1706 if (win->w_llist == NULL) 1707 { 1708 win->w_llist = ll_ref; 1709 ll_ref->qf_refcount++; 1710 } 1711 } 1712 else 1713 { 1714 1715 /* 1716 * Try to find a window that shows the right buffer. 1717 * Default to the window just above the quickfix buffer. 1718 */ 1719 win = curwin; 1720 altwin = NULL; 1721 for (;;) 1722 { 1723 if (win->w_buffer->b_fnum == qf_ptr->qf_fnum) 1724 break; 1725 if (win->w_prev == NULL) 1726 win = lastwin; /* wrap around the top */ 1727 else 1728 win = win->w_prev; /* go to previous window */ 1729 1730 if (IS_QF_WINDOW(win)) 1731 { 1732 /* Didn't find it, go to the window before the quickfix 1733 * window. */ 1734 if (altwin != NULL) 1735 win = altwin; 1736 else if (curwin->w_prev != NULL) 1737 win = curwin->w_prev; 1738 else 1739 win = curwin->w_next; 1740 break; 1741 } 1742 1743 /* Remember a usable window. */ 1744 if (altwin == NULL && !win->w_p_pvw 1745 && win->w_buffer->b_p_bt[0] == NUL) 1746 altwin = win; 1747 } 1748 1749 win_goto(win); 1750 } 1751 } 1752 } 1753#endif 1754 1755 /* 1756 * If there is a file name, 1757 * read the wanted file if needed, and check autowrite etc. 1758 */ 1759 old_curbuf = curbuf; 1760 old_lnum = curwin->w_cursor.lnum; 1761 1762 if (qf_ptr->qf_fnum != 0) 1763 { 1764 if (qf_ptr->qf_type == 1) 1765 { 1766 /* Open help file (do_ecmd() will set b_help flag, readfile() will 1767 * set b_p_ro flag). */ 1768 if (!can_abandon(curbuf, forceit)) 1769 { 1770 EMSG(_(e_nowrtmsg)); 1771 ok = FALSE; 1772 } 1773 else 1774 ok = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1, 1775 ECMD_HIDE + ECMD_SET_HELP, 1776 oldwin == curwin ? curwin : NULL); 1777 } 1778 else 1779 ok = buflist_getfile(qf_ptr->qf_fnum, 1780 (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit); 1781 } 1782 1783 if (ok == OK) 1784 { 1785 /* When not switched to another buffer, still need to set pc mark */ 1786 if (curbuf == old_curbuf) 1787 setpcmark(); 1788 1789 if (qf_ptr->qf_pattern == NULL) 1790 { 1791 /* 1792 * Go to line with error, unless qf_lnum is 0. 1793 */ 1794 i = qf_ptr->qf_lnum; 1795 if (i > 0) 1796 { 1797 if (i > curbuf->b_ml.ml_line_count) 1798 i = curbuf->b_ml.ml_line_count; 1799 curwin->w_cursor.lnum = i; 1800 } 1801 if (qf_ptr->qf_col > 0) 1802 { 1803 curwin->w_cursor.col = qf_ptr->qf_col - 1; 1804 if (qf_ptr->qf_viscol == TRUE) 1805 { 1806 /* 1807 * Check each character from the beginning of the error 1808 * line up to the error column. For each tab character 1809 * found, reduce the error column value by the length of 1810 * a tab character. 1811 */ 1812 line = ml_get_curline(); 1813 screen_col = 0; 1814 for (char_col = 0; char_col < curwin->w_cursor.col; ++char_col) 1815 { 1816 if (*line == NUL) 1817 break; 1818 if (*line++ == '\t') 1819 { 1820 curwin->w_cursor.col -= 7 - (screen_col % 8); 1821 screen_col += 8 - (screen_col % 8); 1822 } 1823 else 1824 ++screen_col; 1825 } 1826 } 1827 check_cursor(); 1828 } 1829 else 1830 beginline(BL_WHITE | BL_FIX); 1831 } 1832 else 1833 { 1834 pos_T save_cursor; 1835 1836 /* Move the cursor to the first line in the buffer */ 1837 save_cursor = curwin->w_cursor; 1838 curwin->w_cursor.lnum = 0; 1839 if (!do_search(NULL, '/', qf_ptr->qf_pattern, (long)1, 1840 SEARCH_KEEP, NULL)) 1841 curwin->w_cursor = save_cursor; 1842 } 1843 1844#ifdef FEAT_FOLDING 1845 if ((fdo_flags & FDO_QUICKFIX) && old_KeyTyped) 1846 foldOpenCursor(); 1847#endif 1848 if (print_message) 1849 { 1850 /* Update the screen before showing the message */ 1851 update_topline_redraw(); 1852 sprintf((char *)IObuff, _("(%d of %d)%s%s: "), qf_index, 1853 qi->qf_lists[qi->qf_curlist].qf_count, 1854 qf_ptr->qf_cleared ? _(" (line deleted)") : "", 1855 (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); 1856 /* Add the message, skipping leading whitespace and newlines. */ 1857 len = (int)STRLEN(IObuff); 1858 qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len); 1859 1860 /* Output the message. Overwrite to avoid scrolling when the 'O' 1861 * flag is present in 'shortmess'; But when not jumping, print the 1862 * whole message. */ 1863 i = msg_scroll; 1864 if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum) 1865 msg_scroll = TRUE; 1866 else if (!msg_scrolled && shortmess(SHM_OVERALL)) 1867 msg_scroll = FALSE; 1868 msg_attr_keep(IObuff, 0, TRUE); 1869 msg_scroll = i; 1870 } 1871 } 1872 else 1873 { 1874#ifdef FEAT_WINDOWS 1875 if (opened_window) 1876 win_close(curwin, TRUE); /* Close opened window */ 1877#endif 1878 if (qf_ptr->qf_fnum != 0) 1879 { 1880 /* 1881 * Couldn't open file, so put index back where it was. This could 1882 * happen if the file was readonly and we changed something. 1883 */ 1884#ifdef FEAT_WINDOWS 1885failed: 1886#endif 1887 qf_ptr = old_qf_ptr; 1888 qf_index = old_qf_index; 1889 } 1890 } 1891theend: 1892 qi->qf_lists[qi->qf_curlist].qf_ptr = qf_ptr; 1893 qi->qf_lists[qi->qf_curlist].qf_index = qf_index; 1894#ifdef FEAT_WINDOWS 1895 if (p_swb != old_swb && opened_window) 1896 { 1897 /* Restore old 'switchbuf' value, but not when an autocommand or 1898 * modeline has changed the value. */ 1899 if (p_swb == empty_option) 1900 { 1901 p_swb = old_swb; 1902 swb_flags = old_swb_flags; 1903 } 1904 else 1905 free_string_option(old_swb); 1906 } 1907#endif 1908} 1909 1910/* 1911 * ":clist": list all errors 1912 * ":llist": list all locations 1913 */ 1914 void 1915qf_list(eap) 1916 exarg_T *eap; 1917{ 1918 buf_T *buf; 1919 char_u *fname; 1920 qfline_T *qfp; 1921 int i; 1922 int idx1 = 1; 1923 int idx2 = -1; 1924 char_u *arg = eap->arg; 1925 int all = eap->forceit; /* if not :cl!, only show 1926 recognised errors */ 1927 qf_info_T *qi = &ql_info; 1928 1929 if (eap->cmdidx == CMD_llist) 1930 { 1931 qi = GET_LOC_LIST(curwin); 1932 if (qi == NULL) 1933 { 1934 EMSG(_(e_loclist)); 1935 return; 1936 } 1937 } 1938 1939 if (qi->qf_curlist >= qi->qf_listcount 1940 || qi->qf_lists[qi->qf_curlist].qf_count == 0) 1941 { 1942 EMSG(_(e_quickfix)); 1943 return; 1944 } 1945 if (!get_list_range(&arg, &idx1, &idx2) || *arg != NUL) 1946 { 1947 EMSG(_(e_trailing)); 1948 return; 1949 } 1950 i = qi->qf_lists[qi->qf_curlist].qf_count; 1951 if (idx1 < 0) 1952 idx1 = (-idx1 > i) ? 0 : idx1 + i + 1; 1953 if (idx2 < 0) 1954 idx2 = (-idx2 > i) ? 0 : idx2 + i + 1; 1955 1956 if (qi->qf_lists[qi->qf_curlist].qf_nonevalid) 1957 all = TRUE; 1958 qfp = qi->qf_lists[qi->qf_curlist].qf_start; 1959 for (i = 1; !got_int && i <= qi->qf_lists[qi->qf_curlist].qf_count; ) 1960 { 1961 if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2) 1962 { 1963 msg_putchar('\n'); 1964 if (got_int) 1965 break; 1966 1967 fname = NULL; 1968 if (qfp->qf_fnum != 0 1969 && (buf = buflist_findnr(qfp->qf_fnum)) != NULL) 1970 { 1971 fname = buf->b_fname; 1972 if (qfp->qf_type == 1) /* :helpgrep */ 1973 fname = gettail(fname); 1974 } 1975 if (fname == NULL) 1976 sprintf((char *)IObuff, "%2d", i); 1977 else 1978 vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", 1979 i, (char *)fname); 1980 msg_outtrans_attr(IObuff, i == qi->qf_lists[qi->qf_curlist].qf_index 1981 ? hl_attr(HLF_L) : hl_attr(HLF_D)); 1982 if (qfp->qf_lnum == 0) 1983 IObuff[0] = NUL; 1984 else if (qfp->qf_col == 0) 1985 sprintf((char *)IObuff, ":%ld", qfp->qf_lnum); 1986 else 1987 sprintf((char *)IObuff, ":%ld col %d", 1988 qfp->qf_lnum, qfp->qf_col); 1989 sprintf((char *)IObuff + STRLEN(IObuff), "%s:", 1990 (char *)qf_types(qfp->qf_type, qfp->qf_nr)); 1991 msg_puts_attr(IObuff, hl_attr(HLF_N)); 1992 if (qfp->qf_pattern != NULL) 1993 { 1994 qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE); 1995 STRCAT(IObuff, ":"); 1996 msg_puts(IObuff); 1997 } 1998 msg_puts((char_u *)" "); 1999 2000 /* Remove newlines and leading whitespace from the text. For an 2001 * unrecognized line keep the indent, the compiler may mark a word 2002 * with ^^^^. */ 2003 qf_fmt_text((fname != NULL || qfp->qf_lnum != 0) 2004 ? skipwhite(qfp->qf_text) : qfp->qf_text, 2005 IObuff, IOSIZE); 2006 msg_prt_line(IObuff, FALSE); 2007 out_flush(); /* show one line at a time */ 2008 } 2009 2010 qfp = qfp->qf_next; 2011 ++i; 2012 ui_breakcheck(); 2013 } 2014} 2015 2016/* 2017 * Remove newlines and leading whitespace from an error message. 2018 * Put the result in "buf[bufsize]". 2019 */ 2020 static void 2021qf_fmt_text(text, buf, bufsize) 2022 char_u *text; 2023 char_u *buf; 2024 int bufsize; 2025{ 2026 int i; 2027 char_u *p = text; 2028 2029 for (i = 0; *p != NUL && i < bufsize - 1; ++i) 2030 { 2031 if (*p == '\n') 2032 { 2033 buf[i] = ' '; 2034 while (*++p != NUL) 2035 if (!vim_iswhite(*p) && *p != '\n') 2036 break; 2037 } 2038 else 2039 buf[i] = *p++; 2040 } 2041 buf[i] = NUL; 2042} 2043 2044/* 2045 * ":colder [count]": Up in the quickfix stack. 2046 * ":cnewer [count]": Down in the quickfix stack. 2047 * ":lolder [count]": Up in the location list stack. 2048 * ":lnewer [count]": Down in the location list stack. 2049 */ 2050 void 2051qf_age(eap) 2052 exarg_T *eap; 2053{ 2054 qf_info_T *qi = &ql_info; 2055 int count; 2056 2057 if (eap->cmdidx == CMD_lolder || eap->cmdidx == CMD_lnewer) 2058 { 2059 qi = GET_LOC_LIST(curwin); 2060 if (qi == NULL) 2061 { 2062 EMSG(_(e_loclist)); 2063 return; 2064 } 2065 } 2066 2067 if (eap->addr_count != 0) 2068 count = eap->line2; 2069 else 2070 count = 1; 2071 while (count--) 2072 { 2073 if (eap->cmdidx == CMD_colder || eap->cmdidx == CMD_lolder) 2074 { 2075 if (qi->qf_curlist == 0) 2076 { 2077 EMSG(_("E380: At bottom of quickfix stack")); 2078 return; 2079 } 2080 --qi->qf_curlist; 2081 } 2082 else 2083 { 2084 if (qi->qf_curlist >= qi->qf_listcount - 1) 2085 { 2086 EMSG(_("E381: At top of quickfix stack")); 2087 return; 2088 } 2089 ++qi->qf_curlist; 2090 } 2091 } 2092 qf_msg(qi); 2093 2094} 2095 2096 static void 2097qf_msg(qi) 2098 qf_info_T *qi; 2099{ 2100 smsg((char_u *)_("error list %d of %d; %d errors"), 2101 qi->qf_curlist + 1, qi->qf_listcount, 2102 qi->qf_lists[qi->qf_curlist].qf_count); 2103#ifdef FEAT_WINDOWS 2104 qf_update_buffer(qi); 2105#endif 2106} 2107 2108/* 2109 * Free error list "idx". 2110 */ 2111 static void 2112qf_free(qi, idx) 2113 qf_info_T *qi; 2114 int idx; 2115{ 2116 qfline_T *qfp; 2117 2118 while (qi->qf_lists[idx].qf_count) 2119 { 2120 qfp = qi->qf_lists[idx].qf_start->qf_next; 2121 vim_free(qi->qf_lists[idx].qf_start->qf_text); 2122 vim_free(qi->qf_lists[idx].qf_start->qf_pattern); 2123 vim_free(qi->qf_lists[idx].qf_start); 2124 qi->qf_lists[idx].qf_start = qfp; 2125 --qi->qf_lists[idx].qf_count; 2126 } 2127 vim_free(qi->qf_lists[idx].qf_title); 2128} 2129 2130/* 2131 * qf_mark_adjust: adjust marks 2132 */ 2133 void 2134qf_mark_adjust(wp, line1, line2, amount, amount_after) 2135 win_T *wp; 2136 linenr_T line1; 2137 linenr_T line2; 2138 long amount; 2139 long amount_after; 2140{ 2141 int i; 2142 qfline_T *qfp; 2143 int idx; 2144 qf_info_T *qi = &ql_info; 2145 2146 if (wp != NULL) 2147 { 2148 if (wp->w_llist == NULL) 2149 return; 2150 qi = wp->w_llist; 2151 } 2152 2153 for (idx = 0; idx < qi->qf_listcount; ++idx) 2154 if (qi->qf_lists[idx].qf_count) 2155 for (i = 0, qfp = qi->qf_lists[idx].qf_start; 2156 i < qi->qf_lists[idx].qf_count; ++i, qfp = qfp->qf_next) 2157 if (qfp->qf_fnum == curbuf->b_fnum) 2158 { 2159 if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) 2160 { 2161 if (amount == MAXLNUM) 2162 qfp->qf_cleared = TRUE; 2163 else 2164 qfp->qf_lnum += amount; 2165 } 2166 else if (amount_after && qfp->qf_lnum > line2) 2167 qfp->qf_lnum += amount_after; 2168 } 2169} 2170 2171/* 2172 * Make a nice message out of the error character and the error number: 2173 * char number message 2174 * e or E 0 " error" 2175 * w or W 0 " warning" 2176 * i or I 0 " info" 2177 * 0 0 "" 2178 * other 0 " c" 2179 * e or E n " error n" 2180 * w or W n " warning n" 2181 * i or I n " info n" 2182 * 0 n " error n" 2183 * other n " c n" 2184 * 1 x "" :helpgrep 2185 */ 2186 static char_u * 2187qf_types(c, nr) 2188 int c, nr; 2189{ 2190 static char_u buf[20]; 2191 static char_u cc[3]; 2192 char_u *p; 2193 2194 if (c == 'W' || c == 'w') 2195 p = (char_u *)" warning"; 2196 else if (c == 'I' || c == 'i') 2197 p = (char_u *)" info"; 2198 else if (c == 'E' || c == 'e' || (c == 0 && nr > 0)) 2199 p = (char_u *)" error"; 2200 else if (c == 0 || c == 1) 2201 p = (char_u *)""; 2202 else 2203 { 2204 cc[0] = ' '; 2205 cc[1] = c; 2206 cc[2] = NUL; 2207 p = cc; 2208 } 2209 2210 if (nr <= 0) 2211 return p; 2212 2213 sprintf((char *)buf, "%s %3d", (char *)p, nr); 2214 return buf; 2215} 2216 2217#if defined(FEAT_WINDOWS) || defined(PROTO) 2218/* 2219 * ":cwindow": open the quickfix window if we have errors to display, 2220 * close it if not. 2221 * ":lwindow": open the location list window if we have locations to display, 2222 * close it if not. 2223 */ 2224 void 2225ex_cwindow(eap) 2226 exarg_T *eap; 2227{ 2228 qf_info_T *qi = &ql_info; 2229 win_T *win; 2230 2231 if (eap->cmdidx == CMD_lwindow) 2232 { 2233 qi = GET_LOC_LIST(curwin); 2234 if (qi == NULL) 2235 return; 2236 } 2237 2238 /* Look for an existing quickfix window. */ 2239 win = qf_find_win(qi); 2240 2241 /* 2242 * If a quickfix window is open but we have no errors to display, 2243 * close the window. If a quickfix window is not open, then open 2244 * it if we have errors; otherwise, leave it closed. 2245 */ 2246 if (qi->qf_lists[qi->qf_curlist].qf_nonevalid 2247 || qi->qf_curlist >= qi->qf_listcount) 2248 { 2249 if (win != NULL) 2250 ex_cclose(eap); 2251 } 2252 else if (win == NULL) 2253 ex_copen(eap); 2254} 2255 2256/* 2257 * ":cclose": close the window showing the list of errors. 2258 * ":lclose": close the window showing the location list 2259 */ 2260 void 2261ex_cclose(eap) 2262 exarg_T *eap; 2263{ 2264 win_T *win = NULL; 2265 qf_info_T *qi = &ql_info; 2266 2267 if (eap->cmdidx == CMD_lclose || eap->cmdidx == CMD_lwindow) 2268 { 2269 qi = GET_LOC_LIST(curwin); 2270 if (qi == NULL) 2271 return; 2272 } 2273 2274 /* Find existing quickfix window and close it. */ 2275 win = qf_find_win(qi); 2276 if (win != NULL) 2277 win_close(win, FALSE); 2278} 2279 2280/* 2281 * ":copen": open a window that shows the list of errors. 2282 * ":lopen": open a window that shows the location list. 2283 */ 2284 void 2285ex_copen(eap) 2286 exarg_T *eap; 2287{ 2288 qf_info_T *qi = &ql_info; 2289 int height; 2290 win_T *win; 2291 tabpage_T *prevtab = curtab; 2292 buf_T *qf_buf; 2293 win_T *oldwin = curwin; 2294 2295 if (eap->cmdidx == CMD_lopen || eap->cmdidx == CMD_lwindow) 2296 { 2297 qi = GET_LOC_LIST(curwin); 2298 if (qi == NULL) 2299 { 2300 EMSG(_(e_loclist)); 2301 return; 2302 } 2303 } 2304 2305 if (eap->addr_count != 0) 2306 height = eap->line2; 2307 else 2308 height = QF_WINHEIGHT; 2309 2310#ifdef FEAT_VISUAL 2311 reset_VIsual_and_resel(); /* stop Visual mode */ 2312#endif 2313#ifdef FEAT_GUI 2314 need_mouse_correct = TRUE; 2315#endif 2316 2317 /* 2318 * Find existing quickfix window, or open a new one. 2319 */ 2320 win = qf_find_win(qi); 2321 2322 if (win != NULL && cmdmod.tab == 0) 2323 win_goto(win); 2324 else 2325 { 2326 qf_buf = qf_find_buf(qi); 2327 2328 /* The current window becomes the previous window afterwards. */ 2329 win = curwin; 2330 2331 if (eap->cmdidx == CMD_copen || eap->cmdidx == CMD_cwindow) 2332 /* Create the new window at the very bottom. */ 2333 win_goto(lastwin); 2334 if (win_split(height, WSP_BELOW | WSP_NEWLOC) == FAIL) 2335 return; /* not enough room for window */ 2336#ifdef FEAT_SCROLLBIND 2337 curwin->w_p_scb = FALSE; 2338#endif 2339 2340 if (eap->cmdidx == CMD_lopen || eap->cmdidx == CMD_lwindow) 2341 { 2342 /* 2343 * For the location list window, create a reference to the 2344 * location list from the window 'win'. 2345 */ 2346 curwin->w_llist_ref = win->w_llist; 2347 win->w_llist->qf_refcount++; 2348 } 2349 2350 if (oldwin != curwin) 2351 oldwin = NULL; /* don't store info when in another window */ 2352 if (qf_buf != NULL) 2353 /* Use the existing quickfix buffer */ 2354 (void)do_ecmd(qf_buf->b_fnum, NULL, NULL, NULL, ECMD_ONE, 2355 ECMD_HIDE + ECMD_OLDBUF, oldwin); 2356 else 2357 { 2358 /* Create a new quickfix buffer */ 2359 (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin); 2360 /* switch off 'swapfile' */ 2361 set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL); 2362 set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix", 2363 OPT_LOCAL); 2364 set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL); 2365#ifdef FEAT_DIFF 2366 curwin->w_p_diff = FALSE; 2367#endif 2368#ifdef FEAT_FOLDING 2369 set_option_value((char_u *)"fdm", 0L, (char_u *)"manual", 2370 OPT_LOCAL); 2371#endif 2372 } 2373 2374 /* Only set the height when still in the same tab page and there is no 2375 * window to the side. */ 2376 if (curtab == prevtab 2377#ifdef FEAT_VERTSPLIT 2378 && curwin->w_width == Columns 2379#endif 2380 ) 2381 win_setheight(height); 2382 curwin->w_p_wfh = TRUE; /* set 'winfixheight' */ 2383 if (win_valid(win)) 2384 prevwin = win; 2385 } 2386 2387 /* 2388 * Fill the buffer with the quickfix list. 2389 */ 2390 qf_fill_buffer(qi); 2391 2392 if (qi->qf_lists[qi->qf_curlist].qf_title != NULL) 2393 set_internal_string_var((char_u *)"w:quickfix_title", 2394 qi->qf_lists[qi->qf_curlist].qf_title); 2395 2396 curwin->w_cursor.lnum = qi->qf_lists[qi->qf_curlist].qf_index; 2397 curwin->w_cursor.col = 0; 2398 check_cursor(); 2399 update_topline(); /* scroll to show the line */ 2400} 2401 2402/* 2403 * Return the number of the current entry (line number in the quickfix 2404 * window). 2405 */ 2406 linenr_T 2407qf_current_entry(wp) 2408 win_T *wp; 2409{ 2410 qf_info_T *qi = &ql_info; 2411 2412 if (IS_LL_WINDOW(wp)) 2413 /* In the location list window, use the referenced location list */ 2414 qi = wp->w_llist_ref; 2415 2416 return qi->qf_lists[qi->qf_curlist].qf_index; 2417} 2418 2419/* 2420 * Update the cursor position in the quickfix window to the current error. 2421 * Return TRUE if there is a quickfix window. 2422 */ 2423 static int 2424qf_win_pos_update(qi, old_qf_index) 2425 qf_info_T *qi; 2426 int old_qf_index; /* previous qf_index or zero */ 2427{ 2428 win_T *win; 2429 int qf_index = qi->qf_lists[qi->qf_curlist].qf_index; 2430 2431 /* 2432 * Put the cursor on the current error in the quickfix window, so that 2433 * it's viewable. 2434 */ 2435 win = qf_find_win(qi); 2436 if (win != NULL 2437 && qf_index <= win->w_buffer->b_ml.ml_line_count 2438 && old_qf_index != qf_index) 2439 { 2440 win_T *old_curwin = curwin; 2441 2442 curwin = win; 2443 curbuf = win->w_buffer; 2444 if (qf_index > old_qf_index) 2445 { 2446 curwin->w_redraw_top = old_qf_index; 2447 curwin->w_redraw_bot = qf_index; 2448 } 2449 else 2450 { 2451 curwin->w_redraw_top = qf_index; 2452 curwin->w_redraw_bot = old_qf_index; 2453 } 2454 curwin->w_cursor.lnum = qf_index; 2455 curwin->w_cursor.col = 0; 2456 update_topline(); /* scroll to show the line */ 2457 redraw_later(VALID); 2458 curwin->w_redr_status = TRUE; /* update ruler */ 2459 curwin = old_curwin; 2460 curbuf = curwin->w_buffer; 2461 } 2462 return win != NULL; 2463} 2464 2465/* 2466 * Check whether the given window is displaying the specified quickfix/location 2467 * list buffer 2468 */ 2469 static int 2470is_qf_win(win, qi) 2471 win_T *win; 2472 qf_info_T *qi; 2473{ 2474 /* 2475 * A window displaying the quickfix buffer will have the w_llist_ref field 2476 * set to NULL. 2477 * A window displaying a location list buffer will have the w_llist_ref 2478 * pointing to the location list. 2479 */ 2480 if (bt_quickfix(win->w_buffer)) 2481 if ((qi == &ql_info && win->w_llist_ref == NULL) 2482 || (qi != &ql_info && win->w_llist_ref == qi)) 2483 return TRUE; 2484 2485 return FALSE; 2486} 2487 2488/* 2489 * Find a window displaying the quickfix/location list 'qi' 2490 * Searches in only the windows opened in the current tab. 2491 */ 2492 static win_T * 2493qf_find_win(qi) 2494 qf_info_T *qi; 2495{ 2496 win_T *win; 2497 2498 FOR_ALL_WINDOWS(win) 2499 if (is_qf_win(win, qi)) 2500 break; 2501 2502 return win; 2503} 2504 2505/* 2506 * Find a quickfix buffer. 2507 * Searches in windows opened in all the tabs. 2508 */ 2509 static buf_T * 2510qf_find_buf(qi) 2511 qf_info_T *qi; 2512{ 2513 tabpage_T *tp; 2514 win_T *win; 2515 2516 FOR_ALL_TAB_WINDOWS(tp, win) 2517 if (is_qf_win(win, qi)) 2518 return win->w_buffer; 2519 2520 return NULL; 2521} 2522 2523/* 2524 * Find the quickfix buffer. If it exists, update the contents. 2525 */ 2526 static void 2527qf_update_buffer(qi) 2528 qf_info_T *qi; 2529{ 2530 buf_T *buf; 2531 aco_save_T aco; 2532 2533 /* Check if a buffer for the quickfix list exists. Update it. */ 2534 buf = qf_find_buf(qi); 2535 if (buf != NULL) 2536 { 2537 /* set curwin/curbuf to buf and save a few things */ 2538 aucmd_prepbuf(&aco, buf); 2539 2540 qf_fill_buffer(qi); 2541 2542 /* restore curwin/curbuf and a few other things */ 2543 aucmd_restbuf(&aco); 2544 2545 (void)qf_win_pos_update(qi, 0); 2546 } 2547} 2548 2549/* 2550 * Fill current buffer with quickfix errors, replacing any previous contents. 2551 * curbuf must be the quickfix buffer! 2552 */ 2553 static void 2554qf_fill_buffer(qi) 2555 qf_info_T *qi; 2556{ 2557 linenr_T lnum; 2558 qfline_T *qfp; 2559 buf_T *errbuf; 2560 int len; 2561 int old_KeyTyped = KeyTyped; 2562 2563 /* delete all existing lines */ 2564 while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) 2565 (void)ml_delete((linenr_T)1, FALSE); 2566 2567 /* Check if there is anything to display */ 2568 if (qi->qf_curlist < qi->qf_listcount) 2569 { 2570 /* Add one line for each error */ 2571 qfp = qi->qf_lists[qi->qf_curlist].qf_start; 2572 for (lnum = 0; lnum < qi->qf_lists[qi->qf_curlist].qf_count; ++lnum) 2573 { 2574 if (qfp->qf_fnum != 0 2575 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL 2576 && errbuf->b_fname != NULL) 2577 { 2578 if (qfp->qf_type == 1) /* :helpgrep */ 2579 STRCPY(IObuff, gettail(errbuf->b_fname)); 2580 else 2581 STRCPY(IObuff, errbuf->b_fname); 2582 len = (int)STRLEN(IObuff); 2583 } 2584 else 2585 len = 0; 2586 IObuff[len++] = '|'; 2587 2588 if (qfp->qf_lnum > 0) 2589 { 2590 sprintf((char *)IObuff + len, "%ld", qfp->qf_lnum); 2591 len += (int)STRLEN(IObuff + len); 2592 2593 if (qfp->qf_col > 0) 2594 { 2595 sprintf((char *)IObuff + len, " col %d", qfp->qf_col); 2596 len += (int)STRLEN(IObuff + len); 2597 } 2598 2599 sprintf((char *)IObuff + len, "%s", 2600 (char *)qf_types(qfp->qf_type, qfp->qf_nr)); 2601 len += (int)STRLEN(IObuff + len); 2602 } 2603 else if (qfp->qf_pattern != NULL) 2604 { 2605 qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len); 2606 len += (int)STRLEN(IObuff + len); 2607 } 2608 IObuff[len++] = '|'; 2609 IObuff[len++] = ' '; 2610 2611 /* Remove newlines and leading whitespace from the text. 2612 * For an unrecognized line keep the indent, the compiler may 2613 * mark a word with ^^^^. */ 2614 qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text, 2615 IObuff + len, IOSIZE - len); 2616 2617 if (ml_append(lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, FALSE) 2618 == FAIL) 2619 break; 2620 qfp = qfp->qf_next; 2621 } 2622 /* Delete the empty line which is now at the end */ 2623 (void)ml_delete(lnum + 1, FALSE); 2624 } 2625 2626 /* correct cursor position */ 2627 check_lnums(TRUE); 2628 2629 /* Set the 'filetype' to "qf" each time after filling the buffer. This 2630 * resembles reading a file into a buffer, it's more logical when using 2631 * autocommands. */ 2632 set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL); 2633 curbuf->b_p_ma = FALSE; 2634 2635#ifdef FEAT_AUTOCMD 2636 keep_filetype = TRUE; /* don't detect 'filetype' */ 2637 apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL, 2638 FALSE, curbuf); 2639 apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL, 2640 FALSE, curbuf); 2641 keep_filetype = FALSE; 2642#endif 2643 2644 /* make sure it will be redrawn */ 2645 redraw_curbuf_later(NOT_VALID); 2646 2647 /* Restore KeyTyped, setting 'filetype' may reset it. */ 2648 KeyTyped = old_KeyTyped; 2649} 2650 2651#endif /* FEAT_WINDOWS */ 2652 2653/* 2654 * Return TRUE if "buf" is the quickfix buffer. 2655 */ 2656 int 2657bt_quickfix(buf) 2658 buf_T *buf; 2659{ 2660 return (buf->b_p_bt[0] == 'q'); 2661} 2662 2663/* 2664 * Return TRUE if "buf" is a "nofile" or "acwrite" buffer. 2665 * This means the buffer name is not a file name. 2666 */ 2667 int 2668bt_nofile(buf) 2669 buf_T *buf; 2670{ 2671 return (buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') 2672 || buf->b_p_bt[0] == 'a'; 2673} 2674 2675/* 2676 * Return TRUE if "buf" is a "nowrite" or "nofile" buffer. 2677 */ 2678 int 2679bt_dontwrite(buf) 2680 buf_T *buf; 2681{ 2682 return (buf->b_p_bt[0] == 'n'); 2683} 2684 2685 int 2686bt_dontwrite_msg(buf) 2687 buf_T *buf; 2688{ 2689 if (bt_dontwrite(buf)) 2690 { 2691 EMSG(_("E382: Cannot write, 'buftype' option is set")); 2692 return TRUE; 2693 } 2694 return FALSE; 2695} 2696 2697/* 2698 * Return TRUE if the buffer should be hidden, according to 'hidden', ":hide" 2699 * and 'bufhidden'. 2700 */ 2701 int 2702buf_hide(buf) 2703 buf_T *buf; 2704{ 2705 /* 'bufhidden' overrules 'hidden' and ":hide", check it first */ 2706 switch (buf->b_p_bh[0]) 2707 { 2708 case 'u': /* "unload" */ 2709 case 'w': /* "wipe" */ 2710 case 'd': return FALSE; /* "delete" */ 2711 case 'h': return TRUE; /* "hide" */ 2712 } 2713 return (p_hid || cmdmod.hide); 2714} 2715 2716/* 2717 * Return TRUE when using ":vimgrep" for ":grep". 2718 */ 2719 int 2720grep_internal(cmdidx) 2721 cmdidx_T cmdidx; 2722{ 2723 return ((cmdidx == CMD_grep 2724 || cmdidx == CMD_lgrep 2725 || cmdidx == CMD_grepadd 2726 || cmdidx == CMD_lgrepadd) 2727 && STRCMP("internal", 2728 *curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0); 2729} 2730 2731/* 2732 * Used for ":make", ":lmake", ":grep", ":lgrep", ":grepadd", and ":lgrepadd" 2733 */ 2734 void 2735ex_make(eap) 2736 exarg_T *eap; 2737{ 2738 char_u *fname; 2739 char_u *cmd; 2740 unsigned len; 2741 win_T *wp = NULL; 2742 qf_info_T *qi = &ql_info; 2743 int res; 2744#ifdef FEAT_AUTOCMD 2745 char_u *au_name = NULL; 2746 2747 switch (eap->cmdidx) 2748 { 2749 case CMD_make: au_name = (char_u *)"make"; break; 2750 case CMD_lmake: au_name = (char_u *)"lmake"; break; 2751 case CMD_grep: au_name = (char_u *)"grep"; break; 2752 case CMD_lgrep: au_name = (char_u *)"lgrep"; break; 2753 case CMD_grepadd: au_name = (char_u *)"grepadd"; break; 2754 case CMD_lgrepadd: au_name = (char_u *)"lgrepadd"; break; 2755 default: break; 2756 } 2757 if (au_name != NULL) 2758 { 2759 apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, 2760 curbuf->b_fname, TRUE, curbuf); 2761# ifdef FEAT_EVAL 2762 if (did_throw || force_abort) 2763 return; 2764# endif 2765 } 2766#endif 2767 2768 /* Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal". */ 2769 if (grep_internal(eap->cmdidx)) 2770 { 2771 ex_vimgrep(eap); 2772 return; 2773 } 2774 2775 if (eap->cmdidx == CMD_lmake || eap->cmdidx == CMD_lgrep 2776 || eap->cmdidx == CMD_lgrepadd) 2777 wp = curwin; 2778 2779 autowrite_all(); 2780 fname = get_mef_name(); 2781 if (fname == NULL) 2782 return; 2783 mch_remove(fname); /* in case it's not unique */ 2784 2785 /* 2786 * If 'shellpipe' empty: don't redirect to 'errorfile'. 2787 */ 2788 len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(eap->arg) + 1; 2789 if (*p_sp != NUL) 2790 len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(fname) + 3; 2791 cmd = alloc(len); 2792 if (cmd == NULL) 2793 return; 2794 sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)eap->arg, 2795 (char *)p_shq); 2796 if (*p_sp != NUL) 2797 append_redir(cmd, len, p_sp, fname); 2798 /* 2799 * Output a newline if there's something else than the :make command that 2800 * was typed (in which case the cursor is in column 0). 2801 */ 2802 if (msg_col == 0) 2803 msg_didout = FALSE; 2804 msg_start(); 2805 MSG_PUTS(":!"); 2806 msg_outtrans(cmd); /* show what we are doing */ 2807 2808 /* let the shell know if we are redirecting output or not */ 2809 do_shell(cmd, *p_sp != NUL ? SHELL_DOOUT : 0); 2810 2811#ifdef AMIGA 2812 out_flush(); 2813 /* read window status report and redraw before message */ 2814 (void)char_avail(); 2815#endif 2816 2817 res = qf_init(wp, fname, (eap->cmdidx != CMD_make 2818 && eap->cmdidx != CMD_lmake) ? p_gefm : p_efm, 2819 (eap->cmdidx != CMD_grepadd 2820 && eap->cmdidx != CMD_lgrepadd), 2821 *eap->cmdlinep); 2822#ifdef FEAT_AUTOCMD 2823 if (au_name != NULL) 2824 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, 2825 curbuf->b_fname, TRUE, curbuf); 2826#endif 2827 if (res > 0 && !eap->forceit) 2828 { 2829 if (wp != NULL) 2830 qi = GET_LOC_LIST(wp); 2831 qf_jump(qi, 0, 0, FALSE); /* display first error */ 2832 } 2833 2834 mch_remove(fname); 2835 vim_free(fname); 2836 vim_free(cmd); 2837} 2838 2839/* 2840 * Return the name for the errorfile, in allocated memory. 2841 * Find a new unique name when 'makeef' contains "##". 2842 * Returns NULL for error. 2843 */ 2844 static char_u * 2845get_mef_name() 2846{ 2847 char_u *p; 2848 char_u *name; 2849 static int start = -1; 2850 static int off = 0; 2851#ifdef HAVE_LSTAT 2852 struct stat sb; 2853#endif 2854 2855 if (*p_mef == NUL) 2856 { 2857 name = vim_tempname('e'); 2858 if (name == NULL) 2859 EMSG(_(e_notmp)); 2860 return name; 2861 } 2862 2863 for (p = p_mef; *p; ++p) 2864 if (p[0] == '#' && p[1] == '#') 2865 break; 2866 2867 if (*p == NUL) 2868 return vim_strsave(p_mef); 2869 2870 /* Keep trying until the name doesn't exist yet. */ 2871 for (;;) 2872 { 2873 if (start == -1) 2874 start = mch_get_pid(); 2875 else 2876 off += 19; 2877 2878 name = alloc((unsigned)STRLEN(p_mef) + 30); 2879 if (name == NULL) 2880 break; 2881 STRCPY(name, p_mef); 2882 sprintf((char *)name + (p - p_mef), "%d%d", start, off); 2883 STRCAT(name, p + 2); 2884 if (mch_getperm(name) < 0 2885#ifdef HAVE_LSTAT 2886 /* Don't accept a symbolic link, its a security risk. */ 2887 && mch_lstat((char *)name, &sb) < 0 2888#endif 2889 ) 2890 break; 2891 vim_free(name); 2892 } 2893 return name; 2894} 2895 2896/* 2897 * ":cc", ":crewind", ":cfirst" and ":clast". 2898 * ":ll", ":lrewind", ":lfirst" and ":llast". 2899 */ 2900 void 2901ex_cc(eap) 2902 exarg_T *eap; 2903{ 2904 qf_info_T *qi = &ql_info; 2905 2906 if (eap->cmdidx == CMD_ll 2907 || eap->cmdidx == CMD_lrewind 2908 || eap->cmdidx == CMD_lfirst 2909 || eap->cmdidx == CMD_llast) 2910 { 2911 qi = GET_LOC_LIST(curwin); 2912 if (qi == NULL) 2913 { 2914 EMSG(_(e_loclist)); 2915 return; 2916 } 2917 } 2918 2919 qf_jump(qi, 0, 2920 eap->addr_count > 0 2921 ? (int)eap->line2 2922 : (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll) 2923 ? 0 2924 : (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind 2925 || eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst) 2926 ? 1 2927 : 32767, 2928 eap->forceit); 2929} 2930 2931/* 2932 * ":cnext", ":cnfile", ":cNext" and ":cprevious". 2933 * ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile". 2934 */ 2935 void 2936ex_cnext(eap) 2937 exarg_T *eap; 2938{ 2939 qf_info_T *qi = &ql_info; 2940 2941 if (eap->cmdidx == CMD_lnext 2942 || eap->cmdidx == CMD_lNext 2943 || eap->cmdidx == CMD_lprevious 2944 || eap->cmdidx == CMD_lnfile 2945 || eap->cmdidx == CMD_lNfile 2946 || eap->cmdidx == CMD_lpfile) 2947 { 2948 qi = GET_LOC_LIST(curwin); 2949 if (qi == NULL) 2950 { 2951 EMSG(_(e_loclist)); 2952 return; 2953 } 2954 } 2955 2956 qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext) 2957 ? FORWARD 2958 : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile) 2959 ? FORWARD_FILE 2960 : (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_lpfile 2961 || eap->cmdidx == CMD_cNfile || eap->cmdidx == CMD_lNfile) 2962 ? BACKWARD_FILE 2963 : BACKWARD, 2964 eap->addr_count > 0 ? (int)eap->line2 : 1, eap->forceit); 2965} 2966 2967/* 2968 * ":cfile"/":cgetfile"/":caddfile" commands. 2969 * ":lfile"/":lgetfile"/":laddfile" commands. 2970 */ 2971 void 2972ex_cfile(eap) 2973 exarg_T *eap; 2974{ 2975 win_T *wp = NULL; 2976 qf_info_T *qi = &ql_info; 2977 2978 if (eap->cmdidx == CMD_lfile || eap->cmdidx == CMD_lgetfile 2979 || eap->cmdidx == CMD_laddfile) 2980 wp = curwin; 2981 2982#ifdef FEAT_BROWSE 2983 if (cmdmod.browse) 2984 { 2985 char_u *browse_file = do_browse(0, (char_u *)_("Error file"), eap->arg, 2986 NULL, NULL, BROWSE_FILTER_ALL_FILES, NULL); 2987 if (browse_file == NULL) 2988 return; 2989 set_string_option_direct((char_u *)"ef", -1, browse_file, OPT_FREE, 0); 2990 vim_free(browse_file); 2991 } 2992 else 2993#endif 2994 if (*eap->arg != NUL) 2995 set_string_option_direct((char_u *)"ef", -1, eap->arg, OPT_FREE, 0); 2996 2997 /* 2998 * This function is used by the :cfile, :cgetfile and :caddfile 2999 * commands. 3000 * :cfile always creates a new quickfix list and jumps to the 3001 * first error. 3002 * :cgetfile creates a new quickfix list but doesn't jump to the 3003 * first error. 3004 * :caddfile adds to an existing quickfix list. If there is no 3005 * quickfix list then a new list is created. 3006 */ 3007 if (qf_init(wp, p_ef, p_efm, (eap->cmdidx != CMD_caddfile 3008 && eap->cmdidx != CMD_laddfile), 3009 *eap->cmdlinep) > 0 3010 && (eap->cmdidx == CMD_cfile 3011 || eap->cmdidx == CMD_lfile)) 3012 { 3013 if (wp != NULL) 3014 qi = GET_LOC_LIST(wp); 3015 qf_jump(qi, 0, 0, eap->forceit); /* display first error */ 3016 } 3017} 3018 3019/* 3020 * ":vimgrep {pattern} file(s)" 3021 * ":vimgrepadd {pattern} file(s)" 3022 * ":lvimgrep {pattern} file(s)" 3023 * ":lvimgrepadd {pattern} file(s)" 3024 */ 3025 void 3026ex_vimgrep(eap) 3027 exarg_T *eap; 3028{ 3029 regmmatch_T regmatch; 3030 int fcount; 3031 char_u **fnames; 3032 char_u *fname; 3033 char_u *s; 3034 char_u *p; 3035 int fi; 3036 qf_info_T *qi = &ql_info; 3037 qfline_T *prevp = NULL; 3038 long lnum; 3039 buf_T *buf; 3040 int duplicate_name = FALSE; 3041 int using_dummy; 3042 int redraw_for_dummy = FALSE; 3043 int found_match; 3044 buf_T *first_match_buf = NULL; 3045 time_t seconds = 0; 3046 int save_mls; 3047#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 3048 char_u *save_ei = NULL; 3049#endif 3050 aco_save_T aco; 3051 int flags = 0; 3052 colnr_T col; 3053 long tomatch; 3054 char_u dirname_start[MAXPATHL]; 3055 char_u dirname_now[MAXPATHL]; 3056 char_u *target_dir = NULL; 3057#ifdef FEAT_AUTOCMD 3058 char_u *au_name = NULL; 3059 3060 switch (eap->cmdidx) 3061 { 3062 case CMD_vimgrep: au_name = (char_u *)"vimgrep"; break; 3063 case CMD_lvimgrep: au_name = (char_u *)"lvimgrep"; break; 3064 case CMD_vimgrepadd: au_name = (char_u *)"vimgrepadd"; break; 3065 case CMD_lvimgrepadd: au_name = (char_u *)"lvimgrepadd"; break; 3066 default: break; 3067 } 3068 if (au_name != NULL) 3069 { 3070 apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, 3071 curbuf->b_fname, TRUE, curbuf); 3072 if (did_throw || force_abort) 3073 return; 3074 } 3075#endif 3076 3077 if (eap->cmdidx == CMD_lgrep 3078 || eap->cmdidx == CMD_lvimgrep 3079 || eap->cmdidx == CMD_lgrepadd 3080 || eap->cmdidx == CMD_lvimgrepadd) 3081 { 3082 qi = ll_get_or_alloc_list(curwin); 3083 if (qi == NULL) 3084 return; 3085 } 3086 3087 if (eap->addr_count > 0) 3088 tomatch = eap->line2; 3089 else 3090 tomatch = MAXLNUM; 3091 3092 /* Get the search pattern: either white-separated or enclosed in // */ 3093 regmatch.regprog = NULL; 3094 p = skip_vimgrep_pat(eap->arg, &s, &flags); 3095 if (p == NULL) 3096 { 3097 EMSG(_(e_invalpat)); 3098 goto theend; 3099 } 3100 regmatch.regprog = vim_regcomp(s, RE_MAGIC); 3101 if (regmatch.regprog == NULL) 3102 goto theend; 3103 regmatch.rmm_ic = p_ic; 3104 regmatch.rmm_maxcol = 0; 3105 3106 p = skipwhite(p); 3107 if (*p == NUL) 3108 { 3109 EMSG(_("E683: File name missing or invalid pattern")); 3110 goto theend; 3111 } 3112 3113 if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd && 3114 eap->cmdidx != CMD_vimgrepadd && eap->cmdidx != CMD_lvimgrepadd) 3115 || qi->qf_curlist == qi->qf_listcount) 3116 /* make place for a new list */ 3117 qf_new_list(qi, *eap->cmdlinep); 3118 else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) 3119 /* Adding to existing list, find last entry. */ 3120 for (prevp = qi->qf_lists[qi->qf_curlist].qf_start; 3121 prevp->qf_next != prevp; prevp = prevp->qf_next) 3122 ; 3123 3124 /* parse the list of arguments */ 3125 if (get_arglist_exp(p, &fcount, &fnames) == FAIL) 3126 goto theend; 3127 if (fcount == 0) 3128 { 3129 EMSG(_(e_nomatch)); 3130 goto theend; 3131 } 3132 3133 /* Remember the current directory, because a BufRead autocommand that does 3134 * ":lcd %:p:h" changes the meaning of short path names. */ 3135 mch_dirname(dirname_start, MAXPATHL); 3136 3137 seconds = (time_t)0; 3138 for (fi = 0; fi < fcount && !got_int && tomatch > 0; ++fi) 3139 { 3140 fname = shorten_fname1(fnames[fi]); 3141 if (time(NULL) > seconds) 3142 { 3143 /* Display the file name every second or so, show the user we are 3144 * working on it. */ 3145 seconds = time(NULL); 3146 msg_start(); 3147 p = msg_strtrunc(fname, TRUE); 3148 if (p == NULL) 3149 msg_outtrans(fname); 3150 else 3151 { 3152 msg_outtrans(p); 3153 vim_free(p); 3154 } 3155 msg_clr_eos(); 3156 msg_didout = FALSE; /* overwrite this message */ 3157 msg_nowait = TRUE; /* don't wait for this message */ 3158 msg_col = 0; 3159 out_flush(); 3160 } 3161 3162 buf = buflist_findname_exp(fnames[fi]); 3163 if (buf == NULL || buf->b_ml.ml_mfp == NULL) 3164 { 3165 /* Remember that a buffer with this name already exists. */ 3166 duplicate_name = (buf != NULL); 3167 using_dummy = TRUE; 3168 redraw_for_dummy = TRUE; 3169 3170#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 3171 /* Don't do Filetype autocommands to avoid loading syntax and 3172 * indent scripts, a great speed improvement. */ 3173 save_ei = au_event_disable(",Filetype"); 3174#endif 3175 /* Don't use modelines here, it's useless. */ 3176 save_mls = p_mls; 3177 p_mls = 0; 3178 3179 /* Load file into a buffer, so that 'fileencoding' is detected, 3180 * autocommands applied, etc. */ 3181 buf = load_dummy_buffer(fname); 3182 3183 /* When autocommands changed directory: go back. We assume it was 3184 * ":lcd %:p:h". */ 3185 mch_dirname(dirname_now, MAXPATHL); 3186 if (STRCMP(dirname_start, dirname_now) != 0) 3187 { 3188 exarg_T ea; 3189 3190 ea.arg = dirname_start; 3191 ea.cmdidx = CMD_lcd; 3192 ex_cd(&ea); 3193 } 3194 3195 p_mls = save_mls; 3196#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 3197 au_event_restore(save_ei); 3198#endif 3199 } 3200 else 3201 /* Use existing, loaded buffer. */ 3202 using_dummy = FALSE; 3203 3204 if (buf == NULL) 3205 { 3206 if (!got_int) 3207 smsg((char_u *)_("Cannot open file \"%s\""), fname); 3208 } 3209 else 3210 { 3211 /* Try for a match in all lines of the buffer. 3212 * For ":1vimgrep" look for first match only. */ 3213 found_match = FALSE; 3214 for (lnum = 1; lnum <= buf->b_ml.ml_line_count && tomatch > 0; 3215 ++lnum) 3216 { 3217 col = 0; 3218 while (vim_regexec_multi(®match, curwin, buf, lnum, 3219 col, NULL) > 0) 3220 { 3221 ; 3222 if (qf_add_entry(qi, &prevp, 3223 NULL, /* dir */ 3224 fname, 3225 0, 3226 ml_get_buf(buf, 3227 regmatch.startpos[0].lnum + lnum, FALSE), 3228 regmatch.startpos[0].lnum + lnum, 3229 regmatch.startpos[0].col + 1, 3230 FALSE, /* vis_col */ 3231 NULL, /* search pattern */ 3232 0, /* nr */ 3233 0, /* type */ 3234 TRUE /* valid */ 3235 ) == FAIL) 3236 { 3237 got_int = TRUE; 3238 break; 3239 } 3240 found_match = TRUE; 3241 if (--tomatch == 0) 3242 break; 3243 if ((flags & VGR_GLOBAL) == 0 3244 || regmatch.endpos[0].lnum > 0) 3245 break; 3246 col = regmatch.endpos[0].col 3247 + (col == regmatch.endpos[0].col); 3248 if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, FALSE))) 3249 break; 3250 } 3251 line_breakcheck(); 3252 if (got_int) 3253 break; 3254 } 3255 3256 if (using_dummy) 3257 { 3258 if (found_match && first_match_buf == NULL) 3259 first_match_buf = buf; 3260 if (duplicate_name) 3261 { 3262 /* Never keep a dummy buffer if there is another buffer 3263 * with the same name. */ 3264 wipe_dummy_buffer(buf); 3265 buf = NULL; 3266 } 3267 else if (!cmdmod.hide 3268 || buf->b_p_bh[0] == 'u' /* "unload" */ 3269 || buf->b_p_bh[0] == 'w' /* "wipe" */ 3270 || buf->b_p_bh[0] == 'd') /* "delete" */ 3271 { 3272 /* When no match was found we don't need to remember the 3273 * buffer, wipe it out. If there was a match and it 3274 * wasn't the first one or we won't jump there: only 3275 * unload the buffer. 3276 * Ignore 'hidden' here, because it may lead to having too 3277 * many swap files. */ 3278 if (!found_match) 3279 { 3280 wipe_dummy_buffer(buf); 3281 buf = NULL; 3282 } 3283 else if (buf != first_match_buf || (flags & VGR_NOJUMP)) 3284 { 3285 unload_dummy_buffer(buf); 3286 buf = NULL; 3287 } 3288 } 3289 3290 if (buf != NULL) 3291 { 3292 /* If the buffer is still loaded we need to use the 3293 * directory we jumped to below. */ 3294 if (buf == first_match_buf 3295 && target_dir == NULL 3296 && STRCMP(dirname_start, dirname_now) != 0) 3297 target_dir = vim_strsave(dirname_now); 3298 3299 /* The buffer is still loaded, the Filetype autocommands 3300 * need to be done now, in that buffer. And the modelines 3301 * need to be done (again). But not the window-local 3302 * options! */ 3303 aucmd_prepbuf(&aco, buf); 3304#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 3305 apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, 3306 buf->b_fname, TRUE, buf); 3307#endif 3308 do_modelines(OPT_NOWIN); 3309 aucmd_restbuf(&aco); 3310 } 3311 } 3312 } 3313 } 3314 3315 FreeWild(fcount, fnames); 3316 3317 qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE; 3318 qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start; 3319 qi->qf_lists[qi->qf_curlist].qf_index = 1; 3320 3321#ifdef FEAT_WINDOWS 3322 qf_update_buffer(qi); 3323#endif 3324 3325#ifdef FEAT_AUTOCMD 3326 if (au_name != NULL) 3327 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, 3328 curbuf->b_fname, TRUE, curbuf); 3329#endif 3330 3331 /* Jump to first match. */ 3332 if (qi->qf_lists[qi->qf_curlist].qf_count > 0) 3333 { 3334 if ((flags & VGR_NOJUMP) == 0) 3335 { 3336 buf = curbuf; 3337 qf_jump(qi, 0, 0, eap->forceit); 3338 if (buf != curbuf) 3339 /* If we jumped to another buffer redrawing will already be 3340 * taken care of. */ 3341 redraw_for_dummy = FALSE; 3342 3343 /* Jump to the directory used after loading the buffer. */ 3344 if (curbuf == first_match_buf && target_dir != NULL) 3345 { 3346 exarg_T ea; 3347 3348 ea.arg = target_dir; 3349 ea.cmdidx = CMD_lcd; 3350 ex_cd(&ea); 3351 } 3352 } 3353 } 3354 else 3355 EMSG2(_(e_nomatch2), s); 3356 3357 /* If we loaded a dummy buffer into the current window, the autocommands 3358 * may have messed up things, need to redraw and recompute folds. */ 3359 if (redraw_for_dummy) 3360 { 3361#ifdef FEAT_FOLDING 3362 foldUpdateAll(curwin); 3363#else 3364 redraw_later(NOT_VALID); 3365#endif 3366 } 3367 3368theend: 3369 vim_free(target_dir); 3370 vim_free(regmatch.regprog); 3371} 3372 3373/* 3374 * Skip over the pattern argument of ":vimgrep /pat/[g][j]". 3375 * Put the start of the pattern in "*s", unless "s" is NULL. 3376 * If "flags" is not NULL put the flags in it: VGR_GLOBAL, VGR_NOJUMP. 3377 * If "s" is not NULL terminate the pattern with a NUL. 3378 * Return a pointer to the char just past the pattern plus flags. 3379 */ 3380 char_u * 3381skip_vimgrep_pat(p, s, flags) 3382 char_u *p; 3383 char_u **s; 3384 int *flags; 3385{ 3386 int c; 3387 3388 if (vim_isIDc(*p)) 3389 { 3390 /* ":vimgrep pattern fname" */ 3391 if (s != NULL) 3392 *s = p; 3393 p = skiptowhite(p); 3394 if (s != NULL && *p != NUL) 3395 *p++ = NUL; 3396 } 3397 else 3398 { 3399 /* ":vimgrep /pattern/[g][j] fname" */ 3400 if (s != NULL) 3401 *s = p + 1; 3402 c = *p; 3403 p = skip_regexp(p + 1, c, TRUE, NULL); 3404 if (*p != c) 3405 return NULL; 3406 3407 /* Truncate the pattern. */ 3408 if (s != NULL) 3409 *p = NUL; 3410 ++p; 3411 3412 /* Find the flags */ 3413 while (*p == 'g' || *p == 'j') 3414 { 3415 if (flags != NULL) 3416 { 3417 if (*p == 'g') 3418 *flags |= VGR_GLOBAL; 3419 else 3420 *flags |= VGR_NOJUMP; 3421 } 3422 ++p; 3423 } 3424 } 3425 return p; 3426} 3427 3428/* 3429 * Load file "fname" into a dummy buffer and return the buffer pointer. 3430 * Returns NULL if it fails. 3431 * Must call unload_dummy_buffer() or wipe_dummy_buffer() later! 3432 */ 3433 static buf_T * 3434load_dummy_buffer(fname) 3435 char_u *fname; 3436{ 3437 buf_T *newbuf; 3438 int failed = TRUE; 3439 aco_save_T aco; 3440 3441 /* Allocate a buffer without putting it in the buffer list. */ 3442 newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY); 3443 if (newbuf == NULL) 3444 return NULL; 3445 3446 /* Init the options. */ 3447 buf_copy_options(newbuf, BCO_ENTER | BCO_NOHELP); 3448 3449 /* need to open the memfile before putting the buffer in a window */ 3450 if (ml_open(newbuf) == OK) 3451 { 3452 /* set curwin/curbuf to buf and save a few things */ 3453 aucmd_prepbuf(&aco, newbuf); 3454 3455 /* Need to set the filename for autocommands. */ 3456 (void)setfname(curbuf, fname, NULL, FALSE); 3457 3458 /* Create swap file now to avoid the ATTENTION message. */ 3459 check_need_swap(TRUE); 3460 3461 /* Remove the "dummy" flag, otherwise autocommands may not 3462 * work. */ 3463 curbuf->b_flags &= ~BF_DUMMY; 3464 3465 if (readfile(fname, NULL, 3466 (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, 3467 NULL, READ_NEW | READ_DUMMY) == OK 3468 && !got_int 3469 && !(curbuf->b_flags & BF_NEW)) 3470 { 3471 failed = FALSE; 3472 if (curbuf != newbuf) 3473 { 3474 /* Bloody autocommands changed the buffer! */ 3475 if (buf_valid(newbuf)) 3476 wipe_buffer(newbuf, FALSE); 3477 newbuf = curbuf; 3478 } 3479 } 3480 3481 /* restore curwin/curbuf and a few other things */ 3482 aucmd_restbuf(&aco); 3483 } 3484 3485 if (!buf_valid(newbuf)) 3486 return NULL; 3487 if (failed) 3488 { 3489 wipe_dummy_buffer(newbuf); 3490 return NULL; 3491 } 3492 return newbuf; 3493} 3494 3495/* 3496 * Wipe out the dummy buffer that load_dummy_buffer() created. 3497 */ 3498 static void 3499wipe_dummy_buffer(buf) 3500 buf_T *buf; 3501{ 3502 if (curbuf != buf) /* safety check */ 3503 { 3504#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) 3505 cleanup_T cs; 3506 3507 /* Reset the error/interrupt/exception state here so that aborting() 3508 * returns FALSE when wiping out the buffer. Otherwise it doesn't 3509 * work when got_int is set. */ 3510 enter_cleanup(&cs); 3511#endif 3512 3513 wipe_buffer(buf, FALSE); 3514 3515#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) 3516 /* Restore the error/interrupt/exception state if not discarded by a 3517 * new aborting error, interrupt, or uncaught exception. */ 3518 leave_cleanup(&cs); 3519#endif 3520 } 3521} 3522 3523/* 3524 * Unload the dummy buffer that load_dummy_buffer() created. 3525 */ 3526 static void 3527unload_dummy_buffer(buf) 3528 buf_T *buf; 3529{ 3530 if (curbuf != buf) /* safety check */ 3531 close_buffer(NULL, buf, DOBUF_UNLOAD); 3532} 3533 3534#if defined(FEAT_EVAL) || defined(PROTO) 3535/* 3536 * Add each quickfix error to list "list" as a dictionary. 3537 */ 3538 int 3539get_errorlist(wp, list) 3540 win_T *wp; 3541 list_T *list; 3542{ 3543 qf_info_T *qi = &ql_info; 3544 dict_T *dict; 3545 char_u buf[2]; 3546 qfline_T *qfp; 3547 int i; 3548 int bufnum; 3549 3550 if (wp != NULL) 3551 { 3552 qi = GET_LOC_LIST(wp); 3553 if (qi == NULL) 3554 return FAIL; 3555 } 3556 3557 if (qi->qf_curlist >= qi->qf_listcount 3558 || qi->qf_lists[qi->qf_curlist].qf_count == 0) 3559 return FAIL; 3560 3561 qfp = qi->qf_lists[qi->qf_curlist].qf_start; 3562 for (i = 1; !got_int && i <= qi->qf_lists[qi->qf_curlist].qf_count; ++i) 3563 { 3564 /* Handle entries with a non-existing buffer number. */ 3565 bufnum = qfp->qf_fnum; 3566 if (bufnum != 0 && (buflist_findnr(bufnum) == NULL)) 3567 bufnum = 0; 3568 3569 if ((dict = dict_alloc()) == NULL) 3570 return FAIL; 3571 if (list_append_dict(list, dict) == FAIL) 3572 return FAIL; 3573 3574 buf[0] = qfp->qf_type; 3575 buf[1] = NUL; 3576 if ( dict_add_nr_str(dict, "bufnr", (long)bufnum, NULL) == FAIL 3577 || dict_add_nr_str(dict, "lnum", (long)qfp->qf_lnum, NULL) == FAIL 3578 || dict_add_nr_str(dict, "col", (long)qfp->qf_col, NULL) == FAIL 3579 || dict_add_nr_str(dict, "vcol", (long)qfp->qf_viscol, NULL) == FAIL 3580 || dict_add_nr_str(dict, "nr", (long)qfp->qf_nr, NULL) == FAIL 3581 || dict_add_nr_str(dict, "pattern", 0L, 3582 qfp->qf_pattern == NULL ? (char_u *)"" : qfp->qf_pattern) == FAIL 3583 || dict_add_nr_str(dict, "text", 0L, 3584 qfp->qf_text == NULL ? (char_u *)"" : qfp->qf_text) == FAIL 3585 || dict_add_nr_str(dict, "type", 0L, buf) == FAIL 3586 || dict_add_nr_str(dict, "valid", (long)qfp->qf_valid, NULL) == FAIL) 3587 return FAIL; 3588 3589 qfp = qfp->qf_next; 3590 } 3591 return OK; 3592} 3593 3594/* 3595 * Populate the quickfix list with the items supplied in the list 3596 * of dictionaries. "title" will be copied to w:quickfix_title 3597 */ 3598 int 3599set_errorlist(wp, list, action, title) 3600 win_T *wp; 3601 list_T *list; 3602 int action; 3603 char_u *title; 3604{ 3605 listitem_T *li; 3606 dict_T *d; 3607 char_u *filename, *pattern, *text, *type; 3608 int bufnum; 3609 long lnum; 3610 int col, nr; 3611 int vcol; 3612 qfline_T *prevp = NULL; 3613 int valid, status; 3614 int retval = OK; 3615 qf_info_T *qi = &ql_info; 3616 int did_bufnr_emsg = FALSE; 3617 3618 if (wp != NULL) 3619 { 3620 qi = ll_get_or_alloc_list(wp); 3621 if (qi == NULL) 3622 return FAIL; 3623 } 3624 3625 if (action == ' ' || qi->qf_curlist == qi->qf_listcount) 3626 /* make place for a new list */ 3627 qf_new_list(qi, title); 3628 else if (action == 'a' && qi->qf_lists[qi->qf_curlist].qf_count > 0) 3629 /* Adding to existing list, find last entry. */ 3630 for (prevp = qi->qf_lists[qi->qf_curlist].qf_start; 3631 prevp->qf_next != prevp; prevp = prevp->qf_next) 3632 ; 3633 else if (action == 'r') 3634 qf_free(qi, qi->qf_curlist); 3635 3636 for (li = list->lv_first; li != NULL; li = li->li_next) 3637 { 3638 if (li->li_tv.v_type != VAR_DICT) 3639 continue; /* Skip non-dict items */ 3640 3641 d = li->li_tv.vval.v_dict; 3642 if (d == NULL) 3643 continue; 3644 3645 filename = get_dict_string(d, (char_u *)"filename", TRUE); 3646 bufnum = get_dict_number(d, (char_u *)"bufnr"); 3647 lnum = get_dict_number(d, (char_u *)"lnum"); 3648 col = get_dict_number(d, (char_u *)"col"); 3649 vcol = get_dict_number(d, (char_u *)"vcol"); 3650 nr = get_dict_number(d, (char_u *)"nr"); 3651 type = get_dict_string(d, (char_u *)"type", TRUE); 3652 pattern = get_dict_string(d, (char_u *)"pattern", TRUE); 3653 text = get_dict_string(d, (char_u *)"text", TRUE); 3654 if (text == NULL) 3655 text = vim_strsave((char_u *)""); 3656 3657 valid = TRUE; 3658 if ((filename == NULL && bufnum == 0) || (lnum == 0 && pattern == NULL)) 3659 valid = FALSE; 3660 3661 /* Mark entries with non-existing buffer number as not valid. Give the 3662 * error message only once. */ 3663 if (bufnum != 0 && (buflist_findnr(bufnum) == NULL)) 3664 { 3665 if (!did_bufnr_emsg) 3666 { 3667 did_bufnr_emsg = TRUE; 3668 EMSGN(_("E92: Buffer %ld not found"), bufnum); 3669 } 3670 valid = FALSE; 3671 bufnum = 0; 3672 } 3673 3674 status = qf_add_entry(qi, &prevp, 3675 NULL, /* dir */ 3676 filename, 3677 bufnum, 3678 text, 3679 lnum, 3680 col, 3681 vcol, /* vis_col */ 3682 pattern, /* search pattern */ 3683 nr, 3684 type == NULL ? NUL : *type, 3685 valid); 3686 3687 vim_free(filename); 3688 vim_free(pattern); 3689 vim_free(text); 3690 vim_free(type); 3691 3692 if (status == FAIL) 3693 { 3694 retval = FAIL; 3695 break; 3696 } 3697 } 3698 3699 if (qi->qf_lists[qi->qf_curlist].qf_index == 0) 3700 /* empty list or no valid entry */ 3701 qi->qf_lists[qi->qf_curlist].qf_nonevalid = TRUE; 3702 else 3703 qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE; 3704 qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start; 3705 qi->qf_lists[qi->qf_curlist].qf_index = 1; 3706 3707#ifdef FEAT_WINDOWS 3708 qf_update_buffer(qi); 3709#endif 3710 3711 return retval; 3712} 3713#endif 3714 3715/* 3716 * ":[range]cbuffer [bufnr]" command. 3717 * ":[range]caddbuffer [bufnr]" command. 3718 * ":[range]cgetbuffer [bufnr]" command. 3719 * ":[range]lbuffer [bufnr]" command. 3720 * ":[range]laddbuffer [bufnr]" command. 3721 * ":[range]lgetbuffer [bufnr]" command. 3722 */ 3723 void 3724ex_cbuffer(eap) 3725 exarg_T *eap; 3726{ 3727 buf_T *buf = NULL; 3728 qf_info_T *qi = &ql_info; 3729 3730 if (eap->cmdidx == CMD_lbuffer || eap->cmdidx == CMD_lgetbuffer 3731 || eap->cmdidx == CMD_laddbuffer) 3732 { 3733 qi = ll_get_or_alloc_list(curwin); 3734 if (qi == NULL) 3735 return; 3736 } 3737 3738 if (*eap->arg == NUL) 3739 buf = curbuf; 3740 else if (*skipwhite(skipdigits(eap->arg)) == NUL) 3741 buf = buflist_findnr(atoi((char *)eap->arg)); 3742 if (buf == NULL) 3743 EMSG(_(e_invarg)); 3744 else if (buf->b_ml.ml_mfp == NULL) 3745 EMSG(_("E681: Buffer is not loaded")); 3746 else 3747 { 3748 if (eap->addr_count == 0) 3749 { 3750 eap->line1 = 1; 3751 eap->line2 = buf->b_ml.ml_line_count; 3752 } 3753 if (eap->line1 < 1 || eap->line1 > buf->b_ml.ml_line_count 3754 || eap->line2 < 1 || eap->line2 > buf->b_ml.ml_line_count) 3755 EMSG(_(e_invrange)); 3756 else 3757 { 3758 char_u *qf_title = *eap->cmdlinep; 3759 3760 if (buf->b_sfname) 3761 { 3762 vim_snprintf((char *)IObuff, IOSIZE, "%s (%s)", 3763 (char *)qf_title, (char *)buf->b_sfname); 3764 qf_title = IObuff; 3765 } 3766 3767 if (qf_init_ext(qi, NULL, buf, NULL, p_efm, 3768 (eap->cmdidx != CMD_caddbuffer 3769 && eap->cmdidx != CMD_laddbuffer), 3770 eap->line1, eap->line2, 3771 qf_title) > 0 3772 && (eap->cmdidx == CMD_cbuffer 3773 || eap->cmdidx == CMD_lbuffer)) 3774 qf_jump(qi, 0, 0, eap->forceit); /* display first error */ 3775 } 3776 } 3777} 3778 3779#if defined(FEAT_EVAL) || defined(PROTO) 3780/* 3781 * ":cexpr {expr}", ":cgetexpr {expr}", ":caddexpr {expr}" command. 3782 * ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command. 3783 */ 3784 void 3785ex_cexpr(eap) 3786 exarg_T *eap; 3787{ 3788 typval_T *tv; 3789 qf_info_T *qi = &ql_info; 3790 3791 if (eap->cmdidx == CMD_lexpr || eap->cmdidx == CMD_lgetexpr 3792 || eap->cmdidx == CMD_laddexpr) 3793 { 3794 qi = ll_get_or_alloc_list(curwin); 3795 if (qi == NULL) 3796 return; 3797 } 3798 3799 /* Evaluate the expression. When the result is a string or a list we can 3800 * use it to fill the errorlist. */ 3801 tv = eval_expr(eap->arg, NULL); 3802 if (tv != NULL) 3803 { 3804 if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL) 3805 || (tv->v_type == VAR_LIST && tv->vval.v_list != NULL)) 3806 { 3807 if (qf_init_ext(qi, NULL, NULL, tv, p_efm, 3808 (eap->cmdidx != CMD_caddexpr 3809 && eap->cmdidx != CMD_laddexpr), 3810 (linenr_T)0, (linenr_T)0, *eap->cmdlinep) > 0 3811 && (eap->cmdidx == CMD_cexpr 3812 || eap->cmdidx == CMD_lexpr)) 3813 qf_jump(qi, 0, 0, eap->forceit); /* display first error */ 3814 } 3815 else 3816 EMSG(_("E777: String or List expected")); 3817 free_tv(tv); 3818 } 3819} 3820#endif 3821 3822/* 3823 * ":helpgrep {pattern}" 3824 */ 3825 void 3826ex_helpgrep(eap) 3827 exarg_T *eap; 3828{ 3829 regmatch_T regmatch; 3830 char_u *save_cpo; 3831 char_u *p; 3832 int fcount; 3833 char_u **fnames; 3834 FILE *fd; 3835 int fi; 3836 qfline_T *prevp = NULL; 3837 long lnum; 3838#ifdef FEAT_MULTI_LANG 3839 char_u *lang; 3840#endif 3841 qf_info_T *qi = &ql_info; 3842 int new_qi = FALSE; 3843 win_T *wp; 3844 3845 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ 3846 save_cpo = p_cpo; 3847 p_cpo = empty_option; 3848 3849#ifdef FEAT_MULTI_LANG 3850 /* Check for a specified language */ 3851 lang = check_help_lang(eap->arg); 3852#endif 3853 3854 if (eap->cmdidx == CMD_lhelpgrep) 3855 { 3856 /* Find an existing help window */ 3857 FOR_ALL_WINDOWS(wp) 3858 if (wp->w_buffer != NULL && wp->w_buffer->b_help) 3859 break; 3860 3861 if (wp == NULL) /* Help window not found */ 3862 qi = NULL; 3863 else 3864 qi = wp->w_llist; 3865 3866 if (qi == NULL) 3867 { 3868 /* Allocate a new location list for help text matches */ 3869 if ((qi = ll_new_list()) == NULL) 3870 return; 3871 new_qi = TRUE; 3872 } 3873 } 3874 3875 regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING); 3876 regmatch.rm_ic = FALSE; 3877 if (regmatch.regprog != NULL) 3878 { 3879 /* create a new quickfix list */ 3880 qf_new_list(qi, *eap->cmdlinep); 3881 3882 /* Go through all directories in 'runtimepath' */ 3883 p = p_rtp; 3884 while (*p != NUL && !got_int) 3885 { 3886 copy_option_part(&p, NameBuff, MAXPATHL, ","); 3887 3888 /* Find all "*.txt" and "*.??x" files in the "doc" directory. */ 3889 add_pathsep(NameBuff); 3890 STRCAT(NameBuff, "doc/*.\\(txt\\|??x\\)"); 3891 if (gen_expand_wildcards(1, &NameBuff, &fcount, 3892 &fnames, EW_FILE|EW_SILENT) == OK 3893 && fcount > 0) 3894 { 3895 for (fi = 0; fi < fcount && !got_int; ++fi) 3896 { 3897#ifdef FEAT_MULTI_LANG 3898 /* Skip files for a different language. */ 3899 if (lang != NULL 3900 && STRNICMP(lang, fnames[fi] 3901 + STRLEN(fnames[fi]) - 3, 2) != 0 3902 && !(STRNICMP(lang, "en", 2) == 0 3903 && STRNICMP("txt", fnames[fi] 3904 + STRLEN(fnames[fi]) - 3, 3) == 0)) 3905 continue; 3906#endif 3907 fd = mch_fopen((char *)fnames[fi], "r"); 3908 if (fd != NULL) 3909 { 3910 lnum = 1; 3911 while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) 3912 { 3913 if (vim_regexec(®match, IObuff, (colnr_T)0)) 3914 { 3915 int l = (int)STRLEN(IObuff); 3916 3917 /* remove trailing CR, LF, spaces, etc. */ 3918 while (l > 0 && IObuff[l - 1] <= ' ') 3919 IObuff[--l] = NUL; 3920 3921 if (qf_add_entry(qi, &prevp, 3922 NULL, /* dir */ 3923 fnames[fi], 3924 0, 3925 IObuff, 3926 lnum, 3927 (int)(regmatch.startp[0] - IObuff) 3928 + 1, /* col */ 3929 FALSE, /* vis_col */ 3930 NULL, /* search pattern */ 3931 0, /* nr */ 3932 1, /* type */ 3933 TRUE /* valid */ 3934 ) == FAIL) 3935 { 3936 got_int = TRUE; 3937 break; 3938 } 3939 } 3940 ++lnum; 3941 line_breakcheck(); 3942 } 3943 fclose(fd); 3944 } 3945 } 3946 FreeWild(fcount, fnames); 3947 } 3948 } 3949 vim_free(regmatch.regprog); 3950 3951 qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE; 3952 qi->qf_lists[qi->qf_curlist].qf_ptr = 3953 qi->qf_lists[qi->qf_curlist].qf_start; 3954 qi->qf_lists[qi->qf_curlist].qf_index = 1; 3955 } 3956 3957 if (p_cpo == empty_option) 3958 p_cpo = save_cpo; 3959 else 3960 /* Darn, some plugin changed the value. */ 3961 free_string_option(save_cpo); 3962 3963#ifdef FEAT_WINDOWS 3964 qf_update_buffer(qi); 3965#endif 3966 3967 /* Jump to first match. */ 3968 if (qi->qf_lists[qi->qf_curlist].qf_count > 0) 3969 qf_jump(qi, 0, 0, FALSE); 3970 else 3971 EMSG2(_(e_nomatch2), eap->arg); 3972 3973 if (eap->cmdidx == CMD_lhelpgrep) 3974 { 3975 /* If the help window is not opened or if it already points to the 3976 * correct location list, then free the new location list. */ 3977 if (!curwin->w_buffer->b_help || curwin->w_llist == qi) 3978 { 3979 if (new_qi) 3980 ll_free_all(&qi); 3981 } 3982 else if (curwin->w_llist == NULL) 3983 curwin->w_llist = qi; 3984 } 3985} 3986 3987#endif /* FEAT_QUICKFIX */ 3988