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 18 struct dir_stack_T 19 { 20 struct dir_stack_T *next; 21 char_u *dirname; 22 }; 23 24 static struct dir_stack_T *dir_stack = NULL; 25 26 /* 27 * For each error the next struct is allocated and linked in a list. 28 */ 29 typedef struct qfline_S qfline_T; 30 struct 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 52 static struct qf_list 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 } qf_lists[LISTCOUNT]; 60 61 static int qf_curlist = 0; /* current error list */ 62 static int qf_listcount = 0; /* current number of lists */ 63 64 #define FMT_PATTERNS 10 /* maximum number of % recognized */ 65 66 /* 67 * Structure used to hold the info of one part of 'errorformat' 68 */ 69 struct eformat 70 { 71 regprog_T *prog; /* pre-formatted part of 'errorformat' */ 72 struct eformat *next; /* pointer to next (NULL if last) */ 73 char_u addr[FMT_PATTERNS]; /* indices of used % patterns */ 74 char_u prefix; /* prefix of this format line: */ 75 /* 'D' enter directory */ 76 /* 'X' leave directory */ 77 /* 'A' start of multi-line message */ 78 /* 'E' error message */ 79 /* 'W' warning message */ 80 /* 'I' informational message */ 81 /* 'C' continuation line */ 82 /* 'Z' end of multi-line message */ 83 /* 'G' general, unspecific message */ 84 /* 'P' push file (partial) message */ 85 /* 'Q' pop/quit file (partial) message */ 86 /* 'O' overread (partial) message */ 87 char_u flags; /* additional flags given in prefix */ 88 /* '-' do not include this line */ 89 }; 90 91 static int qf_init_ext __ARGS((char_u *efile, buf_T *buf, typval_T *tv, char_u *errorformat, int newlist, linenr_T lnumfirst, linenr_T lnumlast)); 92 static void qf_new_list __ARGS((void)); 93 static int qf_add_entry __ARGS((qfline_T **prevp, char_u *dir, char_u *fname, char_u *mesg, long lnum, int col, int vis_col, char_u *pattern, int nr, int type, int valid)); 94 static void qf_msg __ARGS((void)); 95 static void qf_free __ARGS((int idx)); 96 static char_u *qf_types __ARGS((int, int)); 97 static int qf_get_fnum __ARGS((char_u *, char_u *)); 98 static char_u *qf_push_dir __ARGS((char_u *, struct dir_stack_T **)); 99 static char_u *qf_pop_dir __ARGS((struct dir_stack_T **)); 100 static char_u *qf_guess_filepath __ARGS((char_u *)); 101 static void qf_fmt_text __ARGS((char_u *text, char_u *buf, int bufsize)); 102 static void qf_clean_dir_stack __ARGS((struct dir_stack_T **)); 103 #ifdef FEAT_WINDOWS 104 static int qf_win_pos_update __ARGS((int old_qf_index)); 105 static buf_T *qf_find_buf __ARGS((void)); 106 static void qf_update_buffer __ARGS((void)); 107 static void qf_fill_buffer __ARGS((void)); 108 #endif 109 static char_u *get_mef_name __ARGS((void)); 110 static buf_T *load_dummy_buffer __ARGS((char_u *fname)); 111 static void wipe_dummy_buffer __ARGS((buf_T *buf)); 112 static void unload_dummy_buffer __ARGS((buf_T *buf)); 113 114 /* 115 * Read the errorfile "efile" into memory, line by line, building the error 116 * list. 117 * Return -1 for error, number of errors for success. 118 */ 119 int 120 qf_init(efile, errorformat, newlist) 121 char_u *efile; 122 char_u *errorformat; 123 int newlist; /* TRUE: start a new error list */ 124 { 125 if (efile == NULL) 126 return FAIL; 127 return qf_init_ext(efile, curbuf, NULL, errorformat, newlist, 128 (linenr_T)0, (linenr_T)0); 129 } 130 131 /* 132 * Read the errorfile "efile" into memory, line by line, building the error 133 * list. 134 * Alternative: when "efile" is null read errors from buffer "buf". 135 * Always use 'errorformat' from "buf" if there is a local value. 136 * Then lnumfirst and lnumlast specify the range of lines to use. 137 * Return -1 for error, number of errors for success. 138 */ 139 static int 140 qf_init_ext(efile, buf, tv, errorformat, newlist, lnumfirst, lnumlast) 141 char_u *efile; 142 buf_T *buf; 143 typval_T *tv; 144 char_u *errorformat; 145 int newlist; /* TRUE: start a new error list */ 146 linenr_T lnumfirst; /* first line number to use */ 147 linenr_T lnumlast; /* last line number to use */ 148 { 149 char_u *namebuf; 150 char_u *errmsg; 151 char_u *pattern; 152 char_u *fmtstr = NULL; 153 int col = 0; 154 char_u use_viscol = FALSE; 155 int type = 0; 156 int valid; 157 linenr_T buflnum = lnumfirst; 158 long lnum = 0L; 159 int enr = 0; 160 FILE *fd = NULL; 161 qfline_T *qfprev = NULL; /* init to make SASC shut up */ 162 char_u *efmp; 163 struct eformat *fmt_first = NULL; 164 struct eformat *fmt_last = NULL; 165 struct eformat *fmt_ptr; 166 char_u *efm; 167 char_u *ptr; 168 char_u *srcptr; 169 int len; 170 int i; 171 int round; 172 int idx = 0; 173 int multiline = FALSE; 174 int multiignore = FALSE; 175 int multiscan = FALSE; 176 int retval = -1; /* default: return error flag */ 177 char_u *directory = NULL; 178 char_u *currfile = NULL; 179 char_u *tail = NULL; 180 char_u *p_str = NULL; 181 listitem_T *p_li = NULL; 182 struct dir_stack_T *file_stack = NULL; 183 regmatch_T regmatch; 184 static struct fmtpattern 185 { 186 char_u convchar; 187 char *pattern; 188 } fmt_pat[FMT_PATTERNS] = 189 { 190 {'f', ".\\+"}, /* only used when at end */ 191 {'n', "\\d\\+"}, 192 {'l', "\\d\\+"}, 193 {'c', "\\d\\+"}, 194 {'t', "."}, 195 {'m', ".\\+"}, 196 {'r', ".*"}, 197 {'p', "[- .]*"}, 198 {'v', "\\d\\+"}, 199 {'s', ".\\+"} 200 }; 201 202 namebuf = alloc(CMDBUFFSIZE + 1); 203 errmsg = alloc(CMDBUFFSIZE + 1); 204 pattern = alloc(CMDBUFFSIZE + 1); 205 if (namebuf == NULL || errmsg == NULL || pattern == NULL) 206 goto qf_init_end; 207 208 if (efile != NULL && (fd = mch_fopen((char *)efile, "r")) == NULL) 209 { 210 EMSG2(_(e_openerrf), efile); 211 goto qf_init_end; 212 } 213 214 if (newlist || qf_curlist == qf_listcount) 215 /* make place for a new list */ 216 qf_new_list(); 217 else if (qf_lists[qf_curlist].qf_count > 0) 218 /* Adding to existing list, find last entry. */ 219 for (qfprev = qf_lists[qf_curlist].qf_start; 220 qfprev->qf_next != qfprev; qfprev = qfprev->qf_next) 221 ; 222 223 /* 224 * Each part of the format string is copied and modified from errorformat to 225 * regex prog. Only a few % characters are allowed. 226 */ 227 /* Use the local value of 'errorformat' if it's set. */ 228 if (errorformat == p_efm && tv == NULL && *buf->b_p_efm != NUL) 229 efm = buf->b_p_efm; 230 else 231 efm = errorformat; 232 /* 233 * Get some space to modify the format string into. 234 */ 235 i = (FMT_PATTERNS * 3) + ((int)STRLEN(efm) << 2); 236 for (round = FMT_PATTERNS; round > 0; ) 237 i += (int)STRLEN(fmt_pat[--round].pattern); 238 #ifdef COLON_IN_FILENAME 239 i += 12; /* "%f" can become twelve chars longer */ 240 #else 241 i += 2; /* "%f" can become two chars longer */ 242 #endif 243 if ((fmtstr = alloc(i)) == NULL) 244 goto error2; 245 246 while (efm[0]) 247 { 248 /* 249 * Allocate a new eformat structure and put it at the end of the list 250 */ 251 fmt_ptr = (struct eformat *)alloc((unsigned)sizeof(struct eformat)); 252 if (fmt_ptr == NULL) 253 goto error2; 254 if (fmt_first == NULL) /* first one */ 255 fmt_first = fmt_ptr; 256 else 257 fmt_last->next = fmt_ptr; 258 fmt_last = fmt_ptr; 259 fmt_ptr->prefix = NUL; 260 fmt_ptr->flags = NUL; 261 fmt_ptr->next = NULL; 262 fmt_ptr->prog = NULL; 263 for (round = FMT_PATTERNS; round > 0; ) 264 fmt_ptr->addr[--round] = NUL; 265 /* round is 0 now */ 266 267 /* 268 * Isolate one part in the 'errorformat' option 269 */ 270 for (len = 0; efm[len] != NUL && efm[len] != ','; ++len) 271 if (efm[len] == '\\' && efm[len + 1] != NUL) 272 ++len; 273 274 /* 275 * Build regexp pattern from current 'errorformat' option 276 */ 277 ptr = fmtstr; 278 *ptr++ = '^'; 279 for (efmp = efm; efmp < efm + len; ++efmp) 280 { 281 if (*efmp == '%') 282 { 283 ++efmp; 284 for (idx = 0; idx < FMT_PATTERNS; ++idx) 285 if (fmt_pat[idx].convchar == *efmp) 286 break; 287 if (idx < FMT_PATTERNS) 288 { 289 if (fmt_ptr->addr[idx]) 290 { 291 sprintf((char *)errmsg, 292 _("E372: Too many %%%c in format string"), *efmp); 293 EMSG(errmsg); 294 goto error2; 295 } 296 if ((idx 297 && idx < 6 298 && vim_strchr((char_u *)"DXOPQ", 299 fmt_ptr->prefix) != NULL) 300 || (idx == 6 301 && vim_strchr((char_u *)"OPQ", 302 fmt_ptr->prefix) == NULL)) 303 { 304 sprintf((char *)errmsg, 305 _("E373: Unexpected %%%c in format string"), *efmp); 306 EMSG(errmsg); 307 goto error2; 308 } 309 fmt_ptr->addr[idx] = (char_u)++round; 310 *ptr++ = '\\'; 311 *ptr++ = '('; 312 #ifdef BACKSLASH_IN_FILENAME 313 if (*efmp == 'f') 314 { 315 /* Also match "c:" in the file name, even when 316 * checking for a colon next: "%f:". 317 * "\%(\a:\)\=" */ 318 STRCPY(ptr, "\\%(\\a:\\)\\="); 319 ptr += 10; 320 } 321 #endif 322 if (*efmp == 'f' && efmp[1] != NUL) 323 { 324 if (efmp[1] != '\\' && efmp[1] != '%') 325 { 326 /* A file name may contain spaces, but this isn't 327 * in "\f". For "%f:%l:%m" there may be a ":" in 328 * the file name. Use ".\{-1,}x" instead (x is 329 * the next character), the requirement that :999: 330 * follows should work. */ 331 STRCPY(ptr, ".\\{-1,}"); 332 ptr += 7; 333 } 334 else 335 { 336 /* File name followed by '\\' or '%': include as 337 * many file name chars as possible. */ 338 STRCPY(ptr, "\\f\\+"); 339 ptr += 4; 340 } 341 } 342 else 343 { 344 srcptr = (char_u *)fmt_pat[idx].pattern; 345 while ((*ptr = *srcptr++) != NUL) 346 ++ptr; 347 } 348 *ptr++ = '\\'; 349 *ptr++ = ')'; 350 } 351 else if (*efmp == '*') 352 { 353 if (*++efmp == '[' || *efmp == '\\') 354 { 355 if ((*ptr++ = *efmp) == '[') /* %*[^a-z0-9] etc. */ 356 { 357 if (efmp[1] == '^') 358 *ptr++ = *++efmp; 359 if (efmp < efm + len) 360 { 361 *ptr++ = *++efmp; /* could be ']' */ 362 while (efmp < efm + len 363 && (*ptr++ = *++efmp) != ']') 364 /* skip */; 365 if (efmp == efm + len) 366 { 367 EMSG(_("E374: Missing ] in format string")); 368 goto error2; 369 } 370 } 371 } 372 else if (efmp < efm + len) /* %*\D, %*\s etc. */ 373 *ptr++ = *++efmp; 374 *ptr++ = '\\'; 375 *ptr++ = '+'; 376 } 377 else 378 { 379 /* TODO: scanf()-like: %*ud, %*3c, %*f, ... ? */ 380 sprintf((char *)errmsg, 381 _("E375: Unsupported %%%c in format string"), *efmp); 382 EMSG(errmsg); 383 goto error2; 384 } 385 } 386 else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) 387 *ptr++ = *efmp; /* regexp magic characters */ 388 else if (*efmp == '#') 389 *ptr++ = '*'; 390 else if (efmp == efm + 1) /* analyse prefix */ 391 { 392 if (vim_strchr((char_u *)"+-", *efmp) != NULL) 393 fmt_ptr->flags = *efmp++; 394 if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) 395 fmt_ptr->prefix = *efmp; 396 else 397 { 398 sprintf((char *)errmsg, 399 _("E376: Invalid %%%c in format string prefix"), *efmp); 400 EMSG(errmsg); 401 goto error2; 402 } 403 } 404 else 405 { 406 sprintf((char *)errmsg, 407 _("E377: Invalid %%%c in format string"), *efmp); 408 EMSG(errmsg); 409 goto error2; 410 } 411 } 412 else /* copy normal character */ 413 { 414 if (*efmp == '\\' && efmp + 1 < efm + len) 415 ++efmp; 416 else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL) 417 *ptr++ = '\\'; /* escape regexp atoms */ 418 if (*efmp) 419 *ptr++ = *efmp; 420 } 421 } 422 *ptr++ = '$'; 423 *ptr = NUL; 424 if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL) 425 goto error2; 426 /* 427 * Advance to next part 428 */ 429 efm = skip_to_option_part(efm + len); /* skip comma and spaces */ 430 } 431 if (fmt_first == NULL) /* nothing found */ 432 { 433 EMSG(_("E378: 'errorformat' contains no pattern")); 434 goto error2; 435 } 436 437 /* 438 * got_int is reset here, because it was probably set when killing the 439 * ":make" command, but we still want to read the errorfile then. 440 */ 441 got_int = FALSE; 442 443 /* Always ignore case when looking for a matching error. */ 444 regmatch.rm_ic = TRUE; 445 446 if (tv != NULL) 447 { 448 if (tv->v_type == VAR_STRING) 449 p_str = tv->vval.v_string; 450 else if (tv->v_type == VAR_LIST) 451 p_li = tv->vval.v_list->lv_first; 452 } 453 454 /* 455 * Read the lines in the error file one by one. 456 * Try to recognize one of the error formats in each line. 457 */ 458 while (!got_int) 459 { 460 /* Get the next line. */ 461 if (fd == NULL) 462 { 463 if (tv != NULL) 464 { 465 int len; 466 467 if (tv->v_type == VAR_STRING) 468 { 469 /* Get the next line from the supplied string */ 470 char_u *p; 471 472 if (!*p_str) /* Reached the end of the string */ 473 break; 474 475 p = vim_strchr(p_str, '\n'); 476 if (p) 477 len = p - p_str + 1; 478 else 479 len = STRLEN(p_str); 480 481 if (len > CMDBUFFSIZE - 2) 482 vim_strncpy(IObuff, p_str, CMDBUFFSIZE - 2); 483 else 484 vim_strncpy(IObuff, p_str, len); 485 486 p_str += len; 487 } 488 else if (tv->v_type == VAR_LIST) 489 { 490 /* Get the next line from the supplied list */ 491 while (p_li && p_li->li_tv.v_type != VAR_STRING) 492 p_li = p_li->li_next; /* Skip non-string items */ 493 494 if (!p_li) /* End of the list */ 495 break; 496 497 len = STRLEN(p_li->li_tv.vval.v_string); 498 if (len > CMDBUFFSIZE - 2) 499 len = CMDBUFFSIZE - 2; 500 501 vim_strncpy(IObuff, p_li->li_tv.vval.v_string, len); 502 503 p_li = p_li->li_next; /* next item */ 504 } 505 } 506 else 507 { 508 /* Get the next line from the supplied buffer */ 509 if (buflnum > lnumlast) 510 break; 511 vim_strncpy(IObuff, ml_get_buf(buf, buflnum++, FALSE), 512 CMDBUFFSIZE - 2); 513 } 514 } 515 else if (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) == NULL) 516 break; 517 518 IObuff[CMDBUFFSIZE - 2] = NUL; /* for very long lines */ 519 if ((efmp = vim_strrchr(IObuff, '\n')) != NULL) 520 *efmp = NUL; 521 #ifdef USE_CRNL 522 if ((efmp = vim_strrchr(IObuff, '\r')) != NULL) 523 *efmp = NUL; 524 #endif 525 526 /* 527 * Try to match each part of 'errorformat' until we find a complete 528 * match or no match. 529 */ 530 valid = TRUE; 531 restofline: 532 for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) 533 { 534 idx = fmt_ptr->prefix; 535 if (multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) 536 continue; 537 namebuf[0] = NUL; 538 pattern[0] = NUL; 539 if (!multiscan) 540 errmsg[0] = NUL; 541 lnum = 0; 542 col = 0; 543 use_viscol = FALSE; 544 enr = -1; 545 type = 0; 546 tail = NULL; 547 548 regmatch.regprog = fmt_ptr->prog; 549 if (vim_regexec(®match, IObuff, (colnr_T)0)) 550 { 551 if ((idx == 'C' || idx == 'Z') && !multiline) 552 continue; 553 if (vim_strchr((char_u *)"EWI", idx) != NULL) 554 type = idx; 555 else 556 type = 0; 557 /* 558 * Extract error message data from matched line 559 */ 560 if ((i = (int)fmt_ptr->addr[0]) > 0) /* %f */ 561 { 562 int c = *regmatch.endp[i]; 563 564 /* Expand ~/file and $HOME/file to full path. */ 565 *regmatch.endp[i] = NUL; 566 expand_env(regmatch.startp[i], namebuf, CMDBUFFSIZE); 567 *regmatch.endp[i] = c; 568 569 if (vim_strchr((char_u *)"OPQ", idx) != NULL 570 && mch_getperm(namebuf) == -1) 571 continue; 572 } 573 if ((i = (int)fmt_ptr->addr[1]) > 0) /* %n */ 574 enr = (int)atol((char *)regmatch.startp[i]); 575 if ((i = (int)fmt_ptr->addr[2]) > 0) /* %l */ 576 lnum = atol((char *)regmatch.startp[i]); 577 if ((i = (int)fmt_ptr->addr[3]) > 0) /* %c */ 578 col = (int)atol((char *)regmatch.startp[i]); 579 if ((i = (int)fmt_ptr->addr[4]) > 0) /* %t */ 580 type = *regmatch.startp[i]; 581 if (fmt_ptr->flags == '+' && !multiscan) /* %+ */ 582 STRCPY(errmsg, IObuff); 583 else if ((i = (int)fmt_ptr->addr[5]) > 0) /* %m */ 584 { 585 len = (int)(regmatch.endp[i] - regmatch.startp[i]); 586 vim_strncpy(errmsg, regmatch.startp[i], len); 587 } 588 if ((i = (int)fmt_ptr->addr[6]) > 0) /* %r */ 589 tail = regmatch.startp[i]; 590 if ((i = (int)fmt_ptr->addr[7]) > 0) /* %p */ 591 { 592 col = (int)(regmatch.endp[i] - regmatch.startp[i] + 1); 593 if (*((char_u *)regmatch.startp[i]) != TAB) 594 use_viscol = TRUE; 595 } 596 if ((i = (int)fmt_ptr->addr[8]) > 0) /* %v */ 597 { 598 col = (int)atol((char *)regmatch.startp[i]); 599 use_viscol = TRUE; 600 } 601 if ((i = (int)fmt_ptr->addr[9]) > 0) /* %s */ 602 { 603 len = (int)(regmatch.endp[i] - regmatch.startp[i]); 604 if (len > CMDBUFFSIZE - 5) 605 len = CMDBUFFSIZE - 5; 606 STRCPY(pattern, "^\\V"); 607 STRNCAT(pattern, regmatch.startp[i], len); 608 pattern[len + 3] = '\\'; 609 pattern[len + 4] = '$'; 610 pattern[len + 5] = NUL; 611 } 612 break; 613 } 614 } 615 multiscan = FALSE; 616 if (!fmt_ptr || idx == 'D' || idx == 'X') 617 { 618 if (fmt_ptr) 619 { 620 if (idx == 'D') /* enter directory */ 621 { 622 if (*namebuf == NUL) 623 { 624 EMSG(_("E379: Missing or empty directory name")); 625 goto error2; 626 } 627 if ((directory = qf_push_dir(namebuf, &dir_stack)) == NULL) 628 goto error2; 629 } 630 else if (idx == 'X') /* leave directory */ 631 directory = qf_pop_dir(&dir_stack); 632 } 633 namebuf[0] = NUL; /* no match found, remove file name */ 634 lnum = 0; /* don't jump to this line */ 635 valid = FALSE; 636 STRCPY(errmsg, IObuff); /* copy whole line to error message */ 637 if (!fmt_ptr) 638 multiline = multiignore = FALSE; 639 } 640 else if (fmt_ptr) 641 { 642 if (vim_strchr((char_u *)"AEWI", idx) != NULL) 643 multiline = TRUE; /* start of a multi-line message */ 644 else if (vim_strchr((char_u *)"CZ", idx) != NULL) 645 { /* continuation of multi-line msg */ 646 if (qfprev == NULL) 647 goto error2; 648 if (*errmsg && !multiignore) 649 { 650 len = (int)STRLEN(qfprev->qf_text); 651 if ((ptr = alloc((unsigned)(len + STRLEN(errmsg) + 2))) 652 == NULL) 653 goto error2; 654 STRCPY(ptr, qfprev->qf_text); 655 vim_free(qfprev->qf_text); 656 qfprev->qf_text = ptr; 657 *(ptr += len) = '\n'; 658 STRCPY(++ptr, errmsg); 659 } 660 if (qfprev->qf_nr == -1) 661 qfprev->qf_nr = enr; 662 if (vim_isprintc(type) && !qfprev->qf_type) 663 qfprev->qf_type = type; /* only printable chars allowed */ 664 if (!qfprev->qf_lnum) 665 qfprev->qf_lnum = lnum; 666 if (!qfprev->qf_col) 667 qfprev->qf_col = col; 668 qfprev->qf_viscol = use_viscol; 669 if (!qfprev->qf_fnum) 670 qfprev->qf_fnum = qf_get_fnum(directory, 671 *namebuf || directory ? namebuf 672 : currfile && valid ? currfile : 0); 673 if (idx == 'Z') 674 multiline = multiignore = FALSE; 675 line_breakcheck(); 676 continue; 677 } 678 else if (vim_strchr((char_u *)"OPQ", idx) != NULL) 679 { 680 /* global file names */ 681 valid = FALSE; 682 if (*namebuf == NUL || mch_getperm(namebuf) >= 0) 683 { 684 if (*namebuf && idx == 'P') 685 currfile = qf_push_dir(namebuf, &file_stack); 686 else if (idx == 'Q') 687 currfile = qf_pop_dir(&file_stack); 688 *namebuf = NUL; 689 if (tail && *tail) 690 { 691 STRCPY(IObuff, skipwhite(tail)); 692 multiscan = TRUE; 693 goto restofline; 694 } 695 } 696 } 697 if (fmt_ptr->flags == '-') /* generally exclude this line */ 698 { 699 if (multiline) 700 multiignore = TRUE; /* also exclude continuation lines */ 701 continue; 702 } 703 } 704 705 if (qf_add_entry(&qfprev, 706 directory, 707 (*namebuf || directory) 708 ? namebuf 709 : ((currfile && valid) ? currfile : (char_u *)NULL), 710 errmsg, 711 lnum, 712 col, 713 use_viscol, 714 pattern, 715 enr, 716 type, 717 valid) == FAIL) 718 goto error2; 719 line_breakcheck(); 720 } 721 if (fd == NULL || !ferror(fd)) 722 { 723 if (qf_lists[qf_curlist].qf_index == 0) /* no valid entry found */ 724 { 725 qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start; 726 qf_lists[qf_curlist].qf_index = 1; 727 qf_lists[qf_curlist].qf_nonevalid = TRUE; 728 } 729 else 730 { 731 qf_lists[qf_curlist].qf_nonevalid = FALSE; 732 if (qf_lists[qf_curlist].qf_ptr == NULL) 733 qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start; 734 } 735 retval = qf_lists[qf_curlist].qf_count; /* return number of matches */ 736 goto qf_init_ok; 737 } 738 EMSG(_(e_readerrf)); 739 error2: 740 qf_free(qf_curlist); 741 qf_listcount--; 742 if (qf_curlist > 0) 743 --qf_curlist; 744 qf_init_ok: 745 if (fd != NULL) 746 fclose(fd); 747 for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first) 748 { 749 fmt_first = fmt_ptr->next; 750 vim_free(fmt_ptr->prog); 751 vim_free(fmt_ptr); 752 } 753 qf_clean_dir_stack(&dir_stack); 754 qf_clean_dir_stack(&file_stack); 755 qf_init_end: 756 vim_free(namebuf); 757 vim_free(errmsg); 758 vim_free(pattern); 759 vim_free(fmtstr); 760 761 #ifdef FEAT_WINDOWS 762 qf_update_buffer(); 763 #endif 764 765 return retval; 766 } 767 768 /* 769 * Prepare for adding a new quickfix list. 770 */ 771 static void 772 qf_new_list() 773 { 774 int i; 775 776 /* 777 * If the current entry is not the last entry, delete entries below 778 * the current entry. This makes it possible to browse in a tree-like 779 * way with ":grep'. 780 */ 781 while (qf_listcount > qf_curlist + 1) 782 qf_free(--qf_listcount); 783 784 /* 785 * When the stack is full, remove to oldest entry 786 * Otherwise, add a new entry. 787 */ 788 if (qf_listcount == LISTCOUNT) 789 { 790 qf_free(0); 791 for (i = 1; i < LISTCOUNT; ++i) 792 qf_lists[i - 1] = qf_lists[i]; 793 qf_curlist = LISTCOUNT - 1; 794 } 795 else 796 qf_curlist = qf_listcount++; 797 qf_lists[qf_curlist].qf_index = 0; 798 qf_lists[qf_curlist].qf_count = 0; 799 } 800 801 #if defined(EXITFREE) || defined(PROTO) 802 void 803 qf_free_all() 804 { 805 int i; 806 807 for (i = 0; i < qf_listcount; ++i) 808 qf_free(i); 809 } 810 #endif 811 812 /* 813 * Add an entry to the end of the list of errors. 814 * Returns OK or FAIL. 815 */ 816 static int 817 qf_add_entry(prevp, dir, fname, mesg, lnum, col, vis_col, pattern, nr, type, 818 valid) 819 qfline_T **prevp; /* pointer to previously added entry or NULL */ 820 char_u *dir; /* optional directory name */ 821 char_u *fname; /* file name or NULL */ 822 char_u *mesg; /* message */ 823 long lnum; /* line number */ 824 int col; /* column */ 825 int vis_col; /* using visual column */ 826 char_u *pattern; /* search pattern */ 827 int nr; /* error number */ 828 int type; /* type character */ 829 int valid; /* valid entry */ 830 { 831 qfline_T *qfp; 832 833 if ((qfp = (qfline_T *)alloc((unsigned)sizeof(qfline_T))) == NULL) 834 return FAIL; 835 qfp->qf_fnum = qf_get_fnum(dir, fname); 836 if ((qfp->qf_text = vim_strsave(mesg)) == NULL) 837 { 838 vim_free(qfp); 839 return FAIL; 840 } 841 qfp->qf_lnum = lnum; 842 qfp->qf_col = col; 843 qfp->qf_viscol = vis_col; 844 if (pattern == NULL || *pattern == NUL) 845 qfp->qf_pattern = NULL; 846 else if ((qfp->qf_pattern = vim_strsave(pattern)) == NULL) 847 { 848 vim_free(qfp->qf_text); 849 vim_free(qfp); 850 return FAIL; 851 } 852 qfp->qf_nr = nr; 853 if (type != 1 && !vim_isprintc(type)) /* only printable chars allowed */ 854 type = 0; 855 qfp->qf_type = type; 856 qfp->qf_valid = valid; 857 858 if (qf_lists[qf_curlist].qf_count == 0) /* first element in the list */ 859 { 860 qf_lists[qf_curlist].qf_start = qfp; 861 qfp->qf_prev = qfp; /* first element points to itself */ 862 } 863 else 864 { 865 qfp->qf_prev = *prevp; 866 (*prevp)->qf_next = qfp; 867 } 868 qfp->qf_next = qfp; /* last element points to itself */ 869 qfp->qf_cleared = FALSE; 870 *prevp = qfp; 871 ++qf_lists[qf_curlist].qf_count; 872 if (qf_lists[qf_curlist].qf_index == 0 && qfp->qf_valid) 873 /* first valid entry */ 874 { 875 qf_lists[qf_curlist].qf_index = qf_lists[qf_curlist].qf_count; 876 qf_lists[qf_curlist].qf_ptr = qfp; 877 } 878 879 return OK; 880 } 881 882 /* 883 * get buffer number for file "dir.name" 884 */ 885 static int 886 qf_get_fnum(directory, fname) 887 char_u *directory; 888 char_u *fname; 889 { 890 if (fname == NULL || *fname == NUL) /* no file name */ 891 return 0; 892 { 893 #ifdef RISCOS 894 /* Name is reported as `main.c', but file is `c.main' */ 895 return ro_buflist_add(fname); 896 #else 897 char_u *ptr; 898 int fnum; 899 900 # ifdef VMS 901 vms_remove_version(fname); 902 # endif 903 # ifdef BACKSLASH_IN_FILENAME 904 if (directory != NULL) 905 slash_adjust(directory); 906 slash_adjust(fname); 907 # endif 908 if (directory != NULL && !vim_isAbsName(fname) 909 && (ptr = concat_fnames(directory, fname, TRUE)) != NULL) 910 { 911 /* 912 * Here we check if the file really exists. 913 * This should normally be true, but if make works without 914 * "leaving directory"-messages we might have missed a 915 * directory change. 916 */ 917 if (mch_getperm(ptr) < 0) 918 { 919 vim_free(ptr); 920 directory = qf_guess_filepath(fname); 921 if (directory) 922 ptr = concat_fnames(directory, fname, TRUE); 923 else 924 ptr = vim_strsave(fname); 925 } 926 /* Use concatenated directory name and file name */ 927 fnum = buflist_add(ptr, 0); 928 vim_free(ptr); 929 return fnum; 930 } 931 return buflist_add(fname, 0); 932 #endif 933 } 934 } 935 936 /* 937 * push dirbuf onto the directory stack and return pointer to actual dir or 938 * NULL on error 939 */ 940 static char_u * 941 qf_push_dir(dirbuf, stackptr) 942 char_u *dirbuf; 943 struct dir_stack_T **stackptr; 944 { 945 struct dir_stack_T *ds_new; 946 struct dir_stack_T *ds_ptr; 947 948 /* allocate new stack element and hook it in */ 949 ds_new = (struct dir_stack_T *)alloc((unsigned)sizeof(struct dir_stack_T)); 950 if (ds_new == NULL) 951 return NULL; 952 953 ds_new->next = *stackptr; 954 *stackptr = ds_new; 955 956 /* store directory on the stack */ 957 if (vim_isAbsName(dirbuf) 958 || (*stackptr)->next == NULL 959 || (*stackptr && dir_stack != *stackptr)) 960 (*stackptr)->dirname = vim_strsave(dirbuf); 961 else 962 { 963 /* Okay we don't have an absolute path. 964 * dirbuf must be a subdir of one of the directories on the stack. 965 * Let's search... 966 */ 967 ds_new = (*stackptr)->next; 968 (*stackptr)->dirname = NULL; 969 while (ds_new) 970 { 971 vim_free((*stackptr)->dirname); 972 (*stackptr)->dirname = concat_fnames(ds_new->dirname, dirbuf, 973 TRUE); 974 if (mch_isdir((*stackptr)->dirname) == TRUE) 975 break; 976 977 ds_new = ds_new->next; 978 } 979 980 /* clean up all dirs we already left */ 981 while ((*stackptr)->next != ds_new) 982 { 983 ds_ptr = (*stackptr)->next; 984 (*stackptr)->next = (*stackptr)->next->next; 985 vim_free(ds_ptr->dirname); 986 vim_free(ds_ptr); 987 } 988 989 /* Nothing found -> it must be on top level */ 990 if (ds_new == NULL) 991 { 992 vim_free((*stackptr)->dirname); 993 (*stackptr)->dirname = vim_strsave(dirbuf); 994 } 995 } 996 997 if ((*stackptr)->dirname != NULL) 998 return (*stackptr)->dirname; 999 else 1000 { 1001 ds_ptr = *stackptr; 1002 *stackptr = (*stackptr)->next; 1003 vim_free(ds_ptr); 1004 return NULL; 1005 } 1006 } 1007 1008 1009 /* 1010 * pop dirbuf from the directory stack and return previous directory or NULL if 1011 * stack is empty 1012 */ 1013 static char_u * 1014 qf_pop_dir(stackptr) 1015 struct dir_stack_T **stackptr; 1016 { 1017 struct dir_stack_T *ds_ptr; 1018 1019 /* TODO: Should we check if dirbuf is the directory on top of the stack? 1020 * What to do if it isn't? */ 1021 1022 /* pop top element and free it */ 1023 if (*stackptr != NULL) 1024 { 1025 ds_ptr = *stackptr; 1026 *stackptr = (*stackptr)->next; 1027 vim_free(ds_ptr->dirname); 1028 vim_free(ds_ptr); 1029 } 1030 1031 /* return NEW top element as current dir or NULL if stack is empty*/ 1032 return *stackptr ? (*stackptr)->dirname : NULL; 1033 } 1034 1035 /* 1036 * clean up directory stack 1037 */ 1038 static void 1039 qf_clean_dir_stack(stackptr) 1040 struct dir_stack_T **stackptr; 1041 { 1042 struct dir_stack_T *ds_ptr; 1043 1044 while ((ds_ptr = *stackptr) != NULL) 1045 { 1046 *stackptr = (*stackptr)->next; 1047 vim_free(ds_ptr->dirname); 1048 vim_free(ds_ptr); 1049 } 1050 } 1051 1052 /* 1053 * Check in which directory of the directory stack the given file can be 1054 * found. 1055 * Returns a pointer to the directory name or NULL if not found 1056 * Cleans up intermediate directory entries. 1057 * 1058 * TODO: How to solve the following problem? 1059 * If we have the this directory tree: 1060 * ./ 1061 * ./aa 1062 * ./aa/bb 1063 * ./bb 1064 * ./bb/x.c 1065 * and make says: 1066 * making all in aa 1067 * making all in bb 1068 * x.c:9: Error 1069 * Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb. 1070 * qf_guess_filepath will return NULL. 1071 */ 1072 static char_u * 1073 qf_guess_filepath(filename) 1074 char_u *filename; 1075 { 1076 struct dir_stack_T *ds_ptr; 1077 struct dir_stack_T *ds_tmp; 1078 char_u *fullname; 1079 1080 /* no dirs on the stack - there's nothing we can do */ 1081 if (dir_stack == NULL) 1082 return NULL; 1083 1084 ds_ptr = dir_stack->next; 1085 fullname = NULL; 1086 while (ds_ptr) 1087 { 1088 vim_free(fullname); 1089 fullname = concat_fnames(ds_ptr->dirname, filename, TRUE); 1090 1091 /* If concat_fnames failed, just go on. The worst thing that can happen 1092 * is that we delete the entire stack. 1093 */ 1094 if ((fullname != NULL) && (mch_getperm(fullname) >= 0)) 1095 break; 1096 1097 ds_ptr = ds_ptr->next; 1098 } 1099 1100 vim_free(fullname); 1101 1102 /* clean up all dirs we already left */ 1103 while (dir_stack->next != ds_ptr) 1104 { 1105 ds_tmp = dir_stack->next; 1106 dir_stack->next = dir_stack->next->next; 1107 vim_free(ds_tmp->dirname); 1108 vim_free(ds_tmp); 1109 } 1110 1111 return ds_ptr==NULL? NULL: ds_ptr->dirname; 1112 1113 } 1114 1115 /* 1116 * jump to a quickfix line 1117 * if dir == FORWARD go "errornr" valid entries forward 1118 * if dir == BACKWARD go "errornr" valid entries backward 1119 * if dir == FORWARD_FILE go "errornr" valid entries files backward 1120 * if dir == BACKWARD_FILE go "errornr" valid entries files backward 1121 * else if "errornr" is zero, redisplay the same line 1122 * else go to entry "errornr" 1123 */ 1124 void 1125 qf_jump(dir, errornr, forceit) 1126 int dir; 1127 int errornr; 1128 int forceit; 1129 { 1130 qfline_T *qf_ptr; 1131 qfline_T *old_qf_ptr; 1132 int qf_index; 1133 int old_qf_fnum; 1134 int old_qf_index; 1135 int prev_index; 1136 static char_u *e_no_more_items = (char_u *)N_("E553: No more items"); 1137 char_u *err = e_no_more_items; 1138 linenr_T i; 1139 buf_T *old_curbuf; 1140 linenr_T old_lnum; 1141 char_u *old_swb = p_swb; 1142 colnr_T screen_col; 1143 colnr_T char_col; 1144 char_u *line; 1145 #ifdef FEAT_WINDOWS 1146 int opened_window = FALSE; 1147 win_T *win; 1148 win_T *altwin; 1149 #endif 1150 int print_message = TRUE; 1151 int len; 1152 #ifdef FEAT_FOLDING 1153 int old_KeyTyped = KeyTyped; /* getting file may reset it */ 1154 #endif 1155 int ok = OK; 1156 1157 if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0) 1158 { 1159 EMSG(_(e_quickfix)); 1160 return; 1161 } 1162 1163 qf_ptr = qf_lists[qf_curlist].qf_ptr; 1164 old_qf_ptr = qf_ptr; 1165 qf_index = qf_lists[qf_curlist].qf_index; 1166 old_qf_index = qf_index; 1167 if (dir == FORWARD || dir == FORWARD_FILE) /* next valid entry */ 1168 { 1169 while (errornr--) 1170 { 1171 old_qf_ptr = qf_ptr; 1172 prev_index = qf_index; 1173 old_qf_fnum = qf_ptr->qf_fnum; 1174 do 1175 { 1176 if (qf_index == qf_lists[qf_curlist].qf_count 1177 || qf_ptr->qf_next == NULL) 1178 { 1179 qf_ptr = old_qf_ptr; 1180 qf_index = prev_index; 1181 if (err != NULL) 1182 { 1183 EMSG(_(err)); 1184 goto theend; 1185 } 1186 errornr = 0; 1187 break; 1188 } 1189 ++qf_index; 1190 qf_ptr = qf_ptr->qf_next; 1191 } while ((!qf_lists[qf_curlist].qf_nonevalid && !qf_ptr->qf_valid) 1192 || (dir == FORWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum)); 1193 err = NULL; 1194 } 1195 } 1196 else if (dir == BACKWARD || dir == BACKWARD_FILE) /* prev. valid entry */ 1197 { 1198 while (errornr--) 1199 { 1200 old_qf_ptr = qf_ptr; 1201 prev_index = qf_index; 1202 old_qf_fnum = qf_ptr->qf_fnum; 1203 do 1204 { 1205 if (qf_index == 1 || qf_ptr->qf_prev == NULL) 1206 { 1207 qf_ptr = old_qf_ptr; 1208 qf_index = prev_index; 1209 if (err != NULL) 1210 { 1211 EMSG(_(err)); 1212 goto theend; 1213 } 1214 errornr = 0; 1215 break; 1216 } 1217 --qf_index; 1218 qf_ptr = qf_ptr->qf_prev; 1219 } while ((!qf_lists[qf_curlist].qf_nonevalid && !qf_ptr->qf_valid) 1220 || (dir == BACKWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum)); 1221 err = NULL; 1222 } 1223 } 1224 else if (errornr != 0) /* go to specified number */ 1225 { 1226 while (errornr < qf_index && qf_index > 1 && qf_ptr->qf_prev != NULL) 1227 { 1228 --qf_index; 1229 qf_ptr = qf_ptr->qf_prev; 1230 } 1231 while (errornr > qf_index && qf_index < qf_lists[qf_curlist].qf_count 1232 && qf_ptr->qf_next != NULL) 1233 { 1234 ++qf_index; 1235 qf_ptr = qf_ptr->qf_next; 1236 } 1237 } 1238 1239 #ifdef FEAT_WINDOWS 1240 qf_lists[qf_curlist].qf_index = qf_index; 1241 if (qf_win_pos_update(old_qf_index)) 1242 /* No need to print the error message if it's visible in the error 1243 * window */ 1244 print_message = FALSE; 1245 1246 /* 1247 * For ":helpgrep" find a help window or open one. 1248 */ 1249 if (qf_ptr->qf_type == 1 && !curwin->w_buffer->b_help) 1250 { 1251 win_T *wp; 1252 int n; 1253 1254 for (wp = firstwin; wp != NULL; wp = wp->w_next) 1255 if (wp->w_buffer != NULL && wp->w_buffer->b_help) 1256 break; 1257 if (wp != NULL && wp->w_buffer->b_nwindows > 0) 1258 win_enter(wp, TRUE); 1259 else 1260 { 1261 /* 1262 * Split off help window; put it at far top if no position 1263 * specified, the current window is vertically split and narrow. 1264 */ 1265 n = WSP_HELP; 1266 # ifdef FEAT_VERTSPLIT 1267 if (cmdmod.split == 0 && curwin->w_width != Columns 1268 && curwin->w_width < 80) 1269 n |= WSP_TOP; 1270 # endif 1271 if (win_split(0, n) == FAIL) 1272 goto theend; 1273 opened_window = TRUE; /* close it when fail */ 1274 1275 if (curwin->w_height < p_hh) 1276 win_setheight((int)p_hh); 1277 } 1278 1279 if (!p_im) 1280 restart_edit = 0; /* don't want insert mode in help file */ 1281 } 1282 1283 /* 1284 * If currently in the quickfix window, find another window to show the 1285 * file in. 1286 */ 1287 if (bt_quickfix(curbuf) && !opened_window) 1288 { 1289 /* 1290 * If there is no file specified, we don't know where to go. 1291 * But do advance, otherwise ":cn" gets stuck. 1292 */ 1293 if (qf_ptr->qf_fnum == 0) 1294 goto theend; 1295 1296 /* 1297 * If there is only one window, create a new one above the quickfix 1298 * window. 1299 */ 1300 if (firstwin == lastwin) 1301 { 1302 if (win_split(0, WSP_ABOVE) == FAIL) 1303 goto failed; /* not enough room for window */ 1304 opened_window = TRUE; /* close it when fail */ 1305 p_swb = empty_option; /* don't split again */ 1306 # ifdef FEAT_SCROLLBIND 1307 curwin->w_p_scb = FALSE; 1308 # endif 1309 } 1310 else 1311 { 1312 /* 1313 * Try to find a window that shows the right buffer. 1314 * Default to the window just above the quickfix buffer. 1315 */ 1316 win = curwin; 1317 altwin = NULL; 1318 for (;;) 1319 { 1320 if (win->w_buffer->b_fnum == qf_ptr->qf_fnum) 1321 break; 1322 if (win->w_prev == NULL) 1323 win = lastwin; /* wrap around the top */ 1324 else 1325 win = win->w_prev; /* go to previous window */ 1326 1327 if (bt_quickfix(win->w_buffer)) 1328 { 1329 /* Didn't find it, go to the window before the quickfix 1330 * window. */ 1331 if (altwin != NULL) 1332 win = altwin; 1333 else if (curwin->w_prev != NULL) 1334 win = curwin->w_prev; 1335 else 1336 win = curwin->w_next; 1337 break; 1338 } 1339 1340 /* Remember a usable window. */ 1341 if (altwin == NULL && !win->w_p_pvw 1342 && win->w_buffer->b_p_bt[0] == NUL) 1343 altwin = win; 1344 } 1345 1346 win_goto(win); 1347 } 1348 } 1349 #endif 1350 1351 /* 1352 * If there is a file name, 1353 * read the wanted file if needed, and check autowrite etc. 1354 */ 1355 old_curbuf = curbuf; 1356 old_lnum = curwin->w_cursor.lnum; 1357 1358 if (qf_ptr->qf_fnum != 0) 1359 { 1360 if (qf_ptr->qf_type == 1) 1361 { 1362 /* Open help file (do_ecmd() will set b_help flag, readfile() will 1363 * set b_p_ro flag). */ 1364 if (!can_abandon(curbuf, forceit)) 1365 { 1366 EMSG(_(e_nowrtmsg)); 1367 ok = FALSE; 1368 } 1369 else 1370 ok = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1, 1371 ECMD_HIDE + ECMD_SET_HELP); 1372 } 1373 else 1374 ok = buflist_getfile(qf_ptr->qf_fnum, 1375 (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit); 1376 } 1377 1378 if (ok == OK) 1379 { 1380 /* When not switched to another buffer, still need to set pc mark */ 1381 if (curbuf == old_curbuf) 1382 setpcmark(); 1383 1384 if (qf_ptr->qf_pattern == NULL) 1385 { 1386 /* 1387 * Go to line with error, unless qf_lnum is 0. 1388 */ 1389 i = qf_ptr->qf_lnum; 1390 if (i > 0) 1391 { 1392 if (i > curbuf->b_ml.ml_line_count) 1393 i = curbuf->b_ml.ml_line_count; 1394 curwin->w_cursor.lnum = i; 1395 } 1396 if (qf_ptr->qf_col > 0) 1397 { 1398 curwin->w_cursor.col = qf_ptr->qf_col - 1; 1399 if (qf_ptr->qf_viscol == TRUE) 1400 { 1401 /* 1402 * Check each character from the beginning of the error 1403 * line up to the error column. For each tab character 1404 * found, reduce the error column value by the length of 1405 * a tab character. 1406 */ 1407 line = ml_get_curline(); 1408 screen_col = 0; 1409 for (char_col = 0; char_col < curwin->w_cursor.col; ++char_col) 1410 { 1411 if (*line == NUL) 1412 break; 1413 if (*line++ == '\t') 1414 { 1415 curwin->w_cursor.col -= 7 - (screen_col % 8); 1416 screen_col += 8 - (screen_col % 8); 1417 } 1418 else 1419 ++screen_col; 1420 } 1421 } 1422 check_cursor(); 1423 } 1424 else 1425 beginline(BL_WHITE | BL_FIX); 1426 } 1427 else 1428 { 1429 pos_T save_cursor; 1430 1431 /* Move the cursor to the first line in the buffer */ 1432 save_cursor = curwin->w_cursor; 1433 curwin->w_cursor.lnum = 0; 1434 if (!do_search(NULL, '/', qf_ptr->qf_pattern, (long)1, SEARCH_KEEP)) 1435 curwin->w_cursor = save_cursor; 1436 } 1437 1438 #ifdef FEAT_FOLDING 1439 if ((fdo_flags & FDO_QUICKFIX) && old_KeyTyped) 1440 foldOpenCursor(); 1441 #endif 1442 if (print_message) 1443 { 1444 /* Update the screen before showing the message */ 1445 update_topline_redraw(); 1446 sprintf((char *)IObuff, _("(%d of %d)%s%s: "), qf_index, 1447 qf_lists[qf_curlist].qf_count, 1448 qf_ptr->qf_cleared ? _(" (line deleted)") : "", 1449 (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); 1450 /* Add the message, skipping leading whitespace and newlines. */ 1451 len = (int)STRLEN(IObuff); 1452 qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len); 1453 1454 /* Output the message. Overwrite to avoid scrolling when the 'O' 1455 * flag is present in 'shortmess'; But when not jumping, print the 1456 * whole message. */ 1457 i = msg_scroll; 1458 if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum) 1459 msg_scroll = TRUE; 1460 else if (!msg_scrolled && shortmess(SHM_OVERALL)) 1461 msg_scroll = FALSE; 1462 msg_attr_keep(IObuff, 0, TRUE); 1463 msg_scroll = i; 1464 } 1465 } 1466 else 1467 { 1468 #ifdef FEAT_WINDOWS 1469 if (opened_window) 1470 win_close(curwin, TRUE); /* Close opened window */ 1471 #endif 1472 if (qf_ptr->qf_fnum != 0) 1473 { 1474 /* 1475 * Couldn't open file, so put index back where it was. This could 1476 * happen if the file was readonly and we changed something. 1477 */ 1478 #ifdef FEAT_WINDOWS 1479 failed: 1480 #endif 1481 qf_ptr = old_qf_ptr; 1482 qf_index = old_qf_index; 1483 } 1484 } 1485 theend: 1486 qf_lists[qf_curlist].qf_ptr = qf_ptr; 1487 qf_lists[qf_curlist].qf_index = qf_index; 1488 #ifdef FEAT_WINDOWS 1489 if (p_swb != old_swb && opened_window) 1490 { 1491 /* Restore old 'switchbuf' value, but not when an autocommand or 1492 * modeline has changed the value. */ 1493 if (p_swb == empty_option) 1494 p_swb = old_swb; 1495 else 1496 free_string_option(old_swb); 1497 } 1498 #endif 1499 } 1500 1501 /* 1502 * ":clist": list all errors 1503 */ 1504 void 1505 qf_list(eap) 1506 exarg_T *eap; 1507 { 1508 buf_T *buf; 1509 char_u *fname; 1510 qfline_T *qfp; 1511 int i; 1512 int idx1 = 1; 1513 int idx2 = -1; 1514 int need_return = TRUE; 1515 char_u *arg = eap->arg; 1516 int all = eap->forceit; /* if not :cl!, only show 1517 recognised errors */ 1518 1519 if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0) 1520 { 1521 EMSG(_(e_quickfix)); 1522 return; 1523 } 1524 if (!get_list_range(&arg, &idx1, &idx2) || *arg != NUL) 1525 { 1526 EMSG(_(e_trailing)); 1527 return; 1528 } 1529 i = qf_lists[qf_curlist].qf_count; 1530 if (idx1 < 0) 1531 idx1 = (-idx1 > i) ? 0 : idx1 + i + 1; 1532 if (idx2 < 0) 1533 idx2 = (-idx2 > i) ? 0 : idx2 + i + 1; 1534 1535 if (qf_lists[qf_curlist].qf_nonevalid) 1536 all = TRUE; 1537 qfp = qf_lists[qf_curlist].qf_start; 1538 for (i = 1; !got_int && i <= qf_lists[qf_curlist].qf_count; ) 1539 { 1540 if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2) 1541 { 1542 if (need_return) 1543 { 1544 msg_putchar('\n'); 1545 if (got_int) 1546 break; 1547 need_return = FALSE; 1548 } 1549 1550 fname = NULL; 1551 if (qfp->qf_fnum != 0 1552 && (buf = buflist_findnr(qfp->qf_fnum)) != NULL) 1553 { 1554 fname = buf->b_fname; 1555 if (qfp->qf_type == 1) /* :helpgrep */ 1556 fname = gettail(fname); 1557 } 1558 if (fname == NULL) 1559 sprintf((char *)IObuff, "%2d", i); 1560 else 1561 vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", 1562 i, (char *)fname); 1563 msg_outtrans_attr(IObuff, i == qf_lists[qf_curlist].qf_index 1564 ? hl_attr(HLF_L) : hl_attr(HLF_D)); 1565 if (qfp->qf_lnum == 0) 1566 IObuff[0] = NUL; 1567 else if (qfp->qf_col == 0) 1568 sprintf((char *)IObuff, ":%ld", qfp->qf_lnum); 1569 else 1570 sprintf((char *)IObuff, ":%ld col %d", 1571 qfp->qf_lnum, qfp->qf_col); 1572 sprintf((char *)IObuff + STRLEN(IObuff), "%s:", 1573 (char *)qf_types(qfp->qf_type, qfp->qf_nr)); 1574 msg_puts_attr(IObuff, hl_attr(HLF_N)); 1575 if (qfp->qf_pattern != NULL) 1576 { 1577 qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE); 1578 STRCAT(IObuff, ":"); 1579 msg_puts(IObuff); 1580 } 1581 msg_puts((char_u *)" "); 1582 1583 /* Remove newlines and leading whitespace from the text. For an 1584 * unrecognized line keep the indent, the compiler may mark a word 1585 * with ^^^^. */ 1586 qf_fmt_text((fname != NULL || qfp->qf_lnum != 0) 1587 ? skipwhite(qfp->qf_text) : qfp->qf_text, 1588 IObuff, IOSIZE); 1589 msg_prt_line(IObuff, FALSE); 1590 out_flush(); /* show one line at a time */ 1591 need_return = TRUE; 1592 } 1593 1594 qfp = qfp->qf_next; 1595 ++i; 1596 ui_breakcheck(); 1597 } 1598 } 1599 1600 /* 1601 * Remove newlines and leading whitespace from an error message. 1602 * Put the result in "buf[bufsize]". 1603 */ 1604 static void 1605 qf_fmt_text(text, buf, bufsize) 1606 char_u *text; 1607 char_u *buf; 1608 int bufsize; 1609 { 1610 int i; 1611 char_u *p = text; 1612 1613 for (i = 0; *p != NUL && i < bufsize - 1; ++i) 1614 { 1615 if (*p == '\n') 1616 { 1617 buf[i] = ' '; 1618 while (*++p != NUL) 1619 if (!vim_iswhite(*p) && *p != '\n') 1620 break; 1621 } 1622 else 1623 buf[i] = *p++; 1624 } 1625 buf[i] = NUL; 1626 } 1627 1628 /* 1629 * ":colder [count]": Up in the quickfix stack. 1630 * ":cnewer [count]": Down in the quickfix stack. 1631 */ 1632 void 1633 qf_age(eap) 1634 exarg_T *eap; 1635 { 1636 int count; 1637 1638 if (eap->addr_count != 0) 1639 count = eap->line2; 1640 else 1641 count = 1; 1642 while (count--) 1643 { 1644 if (eap->cmdidx == CMD_colder) 1645 { 1646 if (qf_curlist == 0) 1647 { 1648 EMSG(_("E380: At bottom of quickfix stack")); 1649 return; 1650 } 1651 --qf_curlist; 1652 } 1653 else 1654 { 1655 if (qf_curlist >= qf_listcount - 1) 1656 { 1657 EMSG(_("E381: At top of quickfix stack")); 1658 return; 1659 } 1660 ++qf_curlist; 1661 } 1662 } 1663 qf_msg(); 1664 } 1665 1666 static void 1667 qf_msg() 1668 { 1669 smsg((char_u *)_("error list %d of %d; %d errors"), 1670 qf_curlist + 1, qf_listcount, qf_lists[qf_curlist].qf_count); 1671 #ifdef FEAT_WINDOWS 1672 qf_update_buffer(); 1673 #endif 1674 } 1675 1676 /* 1677 * Free error list "idx". 1678 */ 1679 static void 1680 qf_free(idx) 1681 int idx; 1682 { 1683 qfline_T *qfp; 1684 1685 while (qf_lists[idx].qf_count) 1686 { 1687 qfp = qf_lists[idx].qf_start->qf_next; 1688 vim_free(qf_lists[idx].qf_start->qf_text); 1689 vim_free(qf_lists[idx].qf_start->qf_pattern); 1690 vim_free(qf_lists[idx].qf_start); 1691 qf_lists[idx].qf_start = qfp; 1692 --qf_lists[idx].qf_count; 1693 } 1694 } 1695 1696 /* 1697 * qf_mark_adjust: adjust marks 1698 */ 1699 void 1700 qf_mark_adjust(line1, line2, amount, amount_after) 1701 linenr_T line1; 1702 linenr_T line2; 1703 long amount; 1704 long amount_after; 1705 { 1706 int i; 1707 qfline_T *qfp; 1708 int idx; 1709 1710 for (idx = 0; idx < qf_listcount; ++idx) 1711 if (qf_lists[idx].qf_count) 1712 for (i = 0, qfp = qf_lists[idx].qf_start; 1713 i < qf_lists[idx].qf_count; ++i, qfp = qfp->qf_next) 1714 if (qfp->qf_fnum == curbuf->b_fnum) 1715 { 1716 if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) 1717 { 1718 if (amount == MAXLNUM) 1719 qfp->qf_cleared = TRUE; 1720 else 1721 qfp->qf_lnum += amount; 1722 } 1723 else if (amount_after && qfp->qf_lnum > line2) 1724 qfp->qf_lnum += amount_after; 1725 } 1726 } 1727 1728 /* 1729 * Make a nice message out of the error character and the error number: 1730 * char number message 1731 * e or E 0 " error" 1732 * w or W 0 " warning" 1733 * i or I 0 " info" 1734 * 0 0 "" 1735 * other 0 " c" 1736 * e or E n " error n" 1737 * w or W n " warning n" 1738 * i or I n " info n" 1739 * 0 n " error n" 1740 * other n " c n" 1741 * 1 x "" :helpgrep 1742 */ 1743 static char_u * 1744 qf_types(c, nr) 1745 int c, nr; 1746 { 1747 static char_u buf[20]; 1748 static char_u cc[3]; 1749 char_u *p; 1750 1751 if (c == 'W' || c == 'w') 1752 p = (char_u *)" warning"; 1753 else if (c == 'I' || c == 'i') 1754 p = (char_u *)" info"; 1755 else if (c == 'E' || c == 'e' || (c == 0 && nr > 0)) 1756 p = (char_u *)" error"; 1757 else if (c == 0 || c == 1) 1758 p = (char_u *)""; 1759 else 1760 { 1761 cc[0] = ' '; 1762 cc[1] = c; 1763 cc[2] = NUL; 1764 p = cc; 1765 } 1766 1767 if (nr <= 0) 1768 return p; 1769 1770 sprintf((char *)buf, "%s %3d", (char *)p, nr); 1771 return buf; 1772 } 1773 1774 #if defined(FEAT_WINDOWS) || defined(PROTO) 1775 /* 1776 * ":cwindow": open the quickfix window if we have errors to display, 1777 * close it if not. 1778 */ 1779 void 1780 ex_cwindow(eap) 1781 exarg_T *eap; 1782 { 1783 win_T *win; 1784 1785 /* 1786 * Look for an existing quickfix window. 1787 */ 1788 for (win = firstwin; win != NULL; win = win->w_next) 1789 if (bt_quickfix(win->w_buffer)) 1790 break; 1791 1792 /* 1793 * If a quickfix window is open but we have no errors to display, 1794 * close the window. If a quickfix window is not open, then open 1795 * it if we have errors; otherwise, leave it closed. 1796 */ 1797 if (qf_lists[qf_curlist].qf_nonevalid || qf_curlist >= qf_listcount) 1798 { 1799 if (win != NULL) 1800 ex_cclose(eap); 1801 } 1802 else if (win == NULL) 1803 ex_copen(eap); 1804 } 1805 1806 /* 1807 * ":cclose": close the window showing the list of errors. 1808 */ 1809 /*ARGSUSED*/ 1810 void 1811 ex_cclose(eap) 1812 exarg_T *eap; 1813 { 1814 win_T *win; 1815 1816 /* 1817 * Find existing quickfix window and close it. 1818 */ 1819 for (win = firstwin; win != NULL; win = win->w_next) 1820 if (bt_quickfix(win->w_buffer)) 1821 break; 1822 1823 if (win != NULL) 1824 win_close(win, FALSE); 1825 } 1826 1827 /* 1828 * ":copen": open a window that shows the list of errors. 1829 */ 1830 void 1831 ex_copen(eap) 1832 exarg_T *eap; 1833 { 1834 int height; 1835 buf_T *buf; 1836 win_T *win; 1837 1838 if (eap->addr_count != 0) 1839 height = eap->line2; 1840 else 1841 height = QF_WINHEIGHT; 1842 1843 #ifdef FEAT_VISUAL 1844 reset_VIsual_and_resel(); /* stop Visual mode */ 1845 #endif 1846 #ifdef FEAT_GUI 1847 need_mouse_correct = TRUE; 1848 #endif 1849 1850 /* 1851 * Find existing quickfix window, or open a new one. 1852 */ 1853 for (win = firstwin; win != NULL; win = win->w_next) 1854 if (bt_quickfix(win->w_buffer)) 1855 break; 1856 if (win != NULL) 1857 win_goto(win); 1858 else 1859 { 1860 /* The current window becomes the previous window afterwards. */ 1861 win = curwin; 1862 1863 /* Create the new window at the very bottom. */ 1864 win_goto(lastwin); 1865 if (win_split(height, WSP_BELOW) == FAIL) 1866 return; /* not enough room for window */ 1867 #ifdef FEAT_SCROLLBIND 1868 curwin->w_p_scb = FALSE; 1869 #endif 1870 1871 /* 1872 * Find existing quickfix buffer, or create a new one. 1873 */ 1874 buf = qf_find_buf(); 1875 if (buf == NULL) 1876 { 1877 (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE); 1878 /* switch off 'swapfile' */ 1879 set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL); 1880 set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix", 1881 OPT_LOCAL); 1882 set_option_value((char_u *)"bh", 0L, (char_u *)"delete", OPT_LOCAL); 1883 set_option_value((char_u *)"diff", 0L, (char_u *)"", OPT_LOCAL); 1884 } 1885 else if (buf != curbuf) 1886 set_curbuf(buf, DOBUF_GOTO); 1887 1888 #ifdef FEAT_VERTSPLIT 1889 /* Only set the height when there is no window to the side. */ 1890 if (curwin->w_width == Columns) 1891 #endif 1892 win_setheight(height); 1893 curwin->w_p_wfh = TRUE; /* set 'winfixheight' */ 1894 if (win_valid(win)) 1895 prevwin = win; 1896 } 1897 1898 /* 1899 * Fill the buffer with the quickfix list. 1900 */ 1901 qf_fill_buffer(); 1902 1903 curwin->w_cursor.lnum = qf_lists[qf_curlist].qf_index; 1904 curwin->w_cursor.col = 0; 1905 check_cursor(); 1906 update_topline(); /* scroll to show the line */ 1907 } 1908 1909 /* 1910 * Return the number of the current entry (line number in the quickfix 1911 * window). 1912 */ 1913 linenr_T 1914 qf_current_entry() 1915 { 1916 return qf_lists[qf_curlist].qf_index; 1917 } 1918 1919 /* 1920 * Update the cursor position in the quickfix window to the current error. 1921 * Return TRUE if there is a quickfix window. 1922 */ 1923 static int 1924 qf_win_pos_update(old_qf_index) 1925 int old_qf_index; /* previous qf_index or zero */ 1926 { 1927 win_T *win; 1928 int qf_index = qf_lists[qf_curlist].qf_index; 1929 1930 /* 1931 * Put the cursor on the current error in the quickfix window, so that 1932 * it's viewable. 1933 */ 1934 for (win = firstwin; win != NULL; win = win->w_next) 1935 if (bt_quickfix(win->w_buffer)) 1936 break; 1937 if (win != NULL 1938 && qf_index <= win->w_buffer->b_ml.ml_line_count 1939 && old_qf_index != qf_index) 1940 { 1941 win_T *old_curwin = curwin; 1942 1943 curwin = win; 1944 curbuf = win->w_buffer; 1945 if (qf_index > old_qf_index) 1946 { 1947 curwin->w_redraw_top = old_qf_index; 1948 curwin->w_redraw_bot = qf_index; 1949 } 1950 else 1951 { 1952 curwin->w_redraw_top = qf_index; 1953 curwin->w_redraw_bot = old_qf_index; 1954 } 1955 curwin->w_cursor.lnum = qf_index; 1956 curwin->w_cursor.col = 0; 1957 update_topline(); /* scroll to show the line */ 1958 redraw_later(VALID); 1959 curwin->w_redr_status = TRUE; /* update ruler */ 1960 curwin = old_curwin; 1961 curbuf = curwin->w_buffer; 1962 } 1963 return win != NULL; 1964 } 1965 1966 /* 1967 * Find quickfix buffer. 1968 */ 1969 static buf_T * 1970 qf_find_buf() 1971 { 1972 buf_T *buf; 1973 1974 for (buf = firstbuf; buf != NULL; buf = buf->b_next) 1975 if (bt_quickfix(buf)) 1976 break; 1977 return buf; 1978 } 1979 1980 /* 1981 * Find the quickfix buffer. If it exists, update the contents. 1982 */ 1983 static void 1984 qf_update_buffer() 1985 { 1986 buf_T *buf; 1987 #ifdef FEAT_AUTOCMD 1988 aco_save_T aco; 1989 #else 1990 buf_T *save_curbuf; 1991 #endif 1992 1993 /* Check if a buffer for the quickfix list exists. Update it. */ 1994 buf = qf_find_buf(); 1995 if (buf != NULL) 1996 { 1997 #ifdef FEAT_AUTOCMD 1998 /* set curwin/curbuf to buf and save a few things */ 1999 aucmd_prepbuf(&aco, buf); 2000 #else 2001 save_curbuf = curbuf; 2002 curbuf = buf; 2003 #endif 2004 2005 qf_fill_buffer(); 2006 2007 #ifdef FEAT_AUTOCMD 2008 /* restore curwin/curbuf and a few other things */ 2009 aucmd_restbuf(&aco); 2010 #else 2011 curbuf = save_curbuf; 2012 #endif 2013 2014 (void)qf_win_pos_update(0); 2015 } 2016 } 2017 2018 /* 2019 * Fill current buffer with quickfix errors, replacing any previous contents. 2020 * curbuf must be the quickfix buffer! 2021 */ 2022 static void 2023 qf_fill_buffer() 2024 { 2025 linenr_T lnum; 2026 qfline_T *qfp; 2027 buf_T *errbuf; 2028 int len; 2029 int old_KeyTyped = KeyTyped; 2030 2031 /* delete all existing lines */ 2032 while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) 2033 (void)ml_delete((linenr_T)1, FALSE); 2034 2035 /* Check if there is anything to display */ 2036 if (qf_curlist < qf_listcount) 2037 { 2038 /* Add one line for each error */ 2039 qfp = qf_lists[qf_curlist].qf_start; 2040 for (lnum = 0; lnum < qf_lists[qf_curlist].qf_count; ++lnum) 2041 { 2042 if (qfp->qf_fnum != 0 2043 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL 2044 && errbuf->b_fname != NULL) 2045 { 2046 if (qfp->qf_type == 1) /* :helpgrep */ 2047 STRCPY(IObuff, gettail(errbuf->b_fname)); 2048 else 2049 STRCPY(IObuff, errbuf->b_fname); 2050 len = (int)STRLEN(IObuff); 2051 } 2052 else 2053 len = 0; 2054 IObuff[len++] = '|'; 2055 2056 if (qfp->qf_lnum > 0) 2057 { 2058 sprintf((char *)IObuff + len, "%ld", qfp->qf_lnum); 2059 len += (int)STRLEN(IObuff + len); 2060 2061 if (qfp->qf_col > 0) 2062 { 2063 sprintf((char *)IObuff + len, " col %d", qfp->qf_col); 2064 len += (int)STRLEN(IObuff + len); 2065 } 2066 2067 sprintf((char *)IObuff + len, "%s", 2068 (char *)qf_types(qfp->qf_type, qfp->qf_nr)); 2069 len += (int)STRLEN(IObuff + len); 2070 } 2071 else if (qfp->qf_pattern != NULL) 2072 { 2073 qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len); 2074 len += (int)STRLEN(IObuff + len); 2075 } 2076 IObuff[len++] = '|'; 2077 IObuff[len++] = ' '; 2078 2079 /* Remove newlines and leading whitespace from the text. 2080 * For an unrecognized line keep the indent, the compiler may 2081 * mark a word with ^^^^. */ 2082 qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text, 2083 IObuff + len, IOSIZE - len); 2084 2085 if (ml_append(lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, FALSE) 2086 == FAIL) 2087 break; 2088 qfp = qfp->qf_next; 2089 } 2090 /* Delete the empty line which is now at the end */ 2091 (void)ml_delete(lnum + 1, FALSE); 2092 } 2093 2094 /* correct cursor position */ 2095 check_lnums(TRUE); 2096 2097 /* Set the 'filetype' to "qf" each time after filling the buffer. This 2098 * resembles reading a file into a buffer, it's more logical when using 2099 * autocommands. */ 2100 set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL); 2101 curbuf->b_p_ma = FALSE; 2102 2103 #ifdef FEAT_AUTOCMD 2104 apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL, 2105 FALSE, curbuf); 2106 apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL, 2107 FALSE, curbuf); 2108 #endif 2109 2110 /* make sure it will be redrawn */ 2111 redraw_curbuf_later(NOT_VALID); 2112 2113 /* Restore KeyTyped, setting 'filetype' may reset it. */ 2114 KeyTyped = old_KeyTyped; 2115 } 2116 2117 #endif /* FEAT_WINDOWS */ 2118 2119 /* 2120 * Return TRUE if "buf" is the quickfix buffer. 2121 */ 2122 int 2123 bt_quickfix(buf) 2124 buf_T *buf; 2125 { 2126 return (buf->b_p_bt[0] == 'q'); 2127 } 2128 2129 /* 2130 * Return TRUE if "buf" is a "nofile" or "acwrite" buffer. 2131 * This means the buffer name is not a file name. 2132 */ 2133 int 2134 bt_nofile(buf) 2135 buf_T *buf; 2136 { 2137 return (buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') 2138 || buf->b_p_bt[0] == 'a'; 2139 } 2140 2141 /* 2142 * Return TRUE if "buf" is a "nowrite" or "nofile" buffer. 2143 */ 2144 int 2145 bt_dontwrite(buf) 2146 buf_T *buf; 2147 { 2148 return (buf->b_p_bt[0] == 'n'); 2149 } 2150 2151 int 2152 bt_dontwrite_msg(buf) 2153 buf_T *buf; 2154 { 2155 if (bt_dontwrite(buf)) 2156 { 2157 EMSG(_("E382: Cannot write, 'buftype' option is set")); 2158 return TRUE; 2159 } 2160 return FALSE; 2161 } 2162 2163 /* 2164 * Return TRUE if the buffer should be hidden, according to 'hidden', ":hide" 2165 * and 'bufhidden'. 2166 */ 2167 int 2168 buf_hide(buf) 2169 buf_T *buf; 2170 { 2171 /* 'bufhidden' overrules 'hidden' and ":hide", check it first */ 2172 switch (buf->b_p_bh[0]) 2173 { 2174 case 'u': /* "unload" */ 2175 case 'w': /* "wipe" */ 2176 case 'd': return FALSE; /* "delete" */ 2177 case 'h': return TRUE; /* "hide" */ 2178 } 2179 return (p_hid || cmdmod.hide); 2180 } 2181 2182 /* 2183 * Return TRUE when using ":vimgrep" for ":grep". 2184 */ 2185 int 2186 grep_internal(cmdidx) 2187 cmdidx_T cmdidx; 2188 { 2189 return ((cmdidx == CMD_grep || cmdidx == CMD_grepadd) 2190 && STRCMP("internal", 2191 *curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0); 2192 } 2193 2194 /* 2195 * Used for ":make", ":grep" and ":grepadd". 2196 */ 2197 void 2198 ex_make(eap) 2199 exarg_T *eap; 2200 { 2201 char_u *fname; 2202 char_u *cmd; 2203 unsigned len; 2204 #ifdef FEAT_AUTOCMD 2205 char_u *au_name = NULL; 2206 2207 switch (eap->cmdidx) 2208 { 2209 case CMD_make: au_name = (char_u *)"make"; break; 2210 case CMD_grep: au_name = (char_u *)"grep"; break; 2211 case CMD_grepadd: au_name = (char_u *)"grepadd"; break; 2212 default: break; 2213 } 2214 if (au_name != NULL) 2215 { 2216 apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, 2217 curbuf->b_fname, TRUE, curbuf); 2218 # ifdef FEAT_EVAL 2219 if (did_throw || force_abort) 2220 return; 2221 # endif 2222 } 2223 #endif 2224 2225 /* Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal". */ 2226 if (grep_internal(eap->cmdidx)) 2227 { 2228 ex_vimgrep(eap); 2229 return; 2230 } 2231 2232 autowrite_all(); 2233 fname = get_mef_name(); 2234 if (fname == NULL) 2235 return; 2236 mch_remove(fname); /* in case it's not unique */ 2237 2238 /* 2239 * If 'shellpipe' empty: don't redirect to 'errorfile'. 2240 */ 2241 len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(eap->arg) + 1; 2242 if (*p_sp != NUL) 2243 len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(fname) + 3; 2244 cmd = alloc(len); 2245 if (cmd == NULL) 2246 return; 2247 sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)eap->arg, 2248 (char *)p_shq); 2249 if (*p_sp != NUL) 2250 append_redir(cmd, p_sp, fname); 2251 /* 2252 * Output a newline if there's something else than the :make command that 2253 * was typed (in which case the cursor is in column 0). 2254 */ 2255 if (msg_col == 0) 2256 msg_didout = FALSE; 2257 msg_start(); 2258 MSG_PUTS(":!"); 2259 msg_outtrans(cmd); /* show what we are doing */ 2260 2261 /* let the shell know if we are redirecting output or not */ 2262 do_shell(cmd, *p_sp != NUL ? SHELL_DOOUT : 0); 2263 2264 #ifdef AMIGA 2265 out_flush(); 2266 /* read window status report and redraw before message */ 2267 (void)char_avail(); 2268 #endif 2269 2270 if (qf_init(fname, eap->cmdidx != CMD_make ? p_gefm : p_efm, 2271 eap->cmdidx != CMD_grepadd) > 0 2272 && !eap->forceit) 2273 qf_jump(0, 0, FALSE); /* display first error */ 2274 2275 mch_remove(fname); 2276 vim_free(fname); 2277 vim_free(cmd); 2278 2279 #ifdef FEAT_AUTOCMD 2280 if (au_name != NULL) 2281 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, 2282 curbuf->b_fname, TRUE, curbuf); 2283 #endif 2284 } 2285 2286 /* 2287 * Return the name for the errorfile, in allocated memory. 2288 * Find a new unique name when 'makeef' contains "##". 2289 * Returns NULL for error. 2290 */ 2291 static char_u * 2292 get_mef_name() 2293 { 2294 char_u *p; 2295 char_u *name; 2296 static int start = -1; 2297 static int off = 0; 2298 #ifdef HAVE_LSTAT 2299 struct stat sb; 2300 #endif 2301 2302 if (*p_mef == NUL) 2303 { 2304 name = vim_tempname('e'); 2305 if (name == NULL) 2306 EMSG(_(e_notmp)); 2307 return name; 2308 } 2309 2310 for (p = p_mef; *p; ++p) 2311 if (p[0] == '#' && p[1] == '#') 2312 break; 2313 2314 if (*p == NUL) 2315 return vim_strsave(p_mef); 2316 2317 /* Keep trying until the name doesn't exist yet. */ 2318 for (;;) 2319 { 2320 if (start == -1) 2321 start = mch_get_pid(); 2322 else 2323 off += 19; 2324 2325 name = alloc((unsigned)STRLEN(p_mef) + 30); 2326 if (name == NULL) 2327 break; 2328 STRCPY(name, p_mef); 2329 sprintf((char *)name + (p - p_mef), "%d%d", start, off); 2330 STRCAT(name, p + 2); 2331 if (mch_getperm(name) < 0 2332 #ifdef HAVE_LSTAT 2333 /* Don't accept a symbolic link, its a security risk. */ 2334 && mch_lstat((char *)name, &sb) < 0 2335 #endif 2336 ) 2337 break; 2338 vim_free(name); 2339 } 2340 return name; 2341 } 2342 2343 /* 2344 * ":cc", ":crewind", ":cfirst" and ":clast". 2345 */ 2346 void 2347 ex_cc(eap) 2348 exarg_T *eap; 2349 { 2350 qf_jump(0, 2351 eap->addr_count > 0 2352 ? (int)eap->line2 2353 : eap->cmdidx == CMD_cc 2354 ? 0 2355 : (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_cfirst) 2356 ? 1 2357 : 32767, 2358 eap->forceit); 2359 } 2360 2361 /* 2362 * ":cnext", ":cnfile", ":cNext" and ":cprevious". 2363 */ 2364 void 2365 ex_cnext(eap) 2366 exarg_T *eap; 2367 { 2368 qf_jump(eap->cmdidx == CMD_cnext 2369 ? FORWARD 2370 : eap->cmdidx == CMD_cnfile 2371 ? FORWARD_FILE 2372 : (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_cNfile) 2373 ? BACKWARD_FILE 2374 : BACKWARD, 2375 eap->addr_count > 0 ? (int)eap->line2 : 1, eap->forceit); 2376 } 2377 2378 /* 2379 * ":cfile"/":cgetfile"/":caddfile" commands. 2380 */ 2381 void 2382 ex_cfile(eap) 2383 exarg_T *eap; 2384 { 2385 if (*eap->arg != NUL) 2386 set_string_option_direct((char_u *)"ef", -1, eap->arg, OPT_FREE); 2387 2388 /* 2389 * This function is used by the :cfile, :cgetfile and :caddfile 2390 * commands. 2391 * :cfile always creates a new quickfix list and jumps to the 2392 * first error. 2393 * :cgetfile creates a new quickfix list but doesn't jump to the 2394 * first error. 2395 * :caddfile adds to an existing quickfix list. If there is no 2396 * quickfix list then a new list is created. 2397 */ 2398 if (qf_init(p_ef, p_efm, eap->cmdidx != CMD_caddfile) > 0 2399 && eap->cmdidx == CMD_cfile) 2400 qf_jump(0, 0, eap->forceit); /* display first error */ 2401 } 2402 2403 /* 2404 * ":vimgrep {pattern} file(s)" 2405 */ 2406 void 2407 ex_vimgrep(eap) 2408 exarg_T *eap; 2409 { 2410 regmmatch_T regmatch; 2411 int fcount; 2412 char_u **fnames; 2413 char_u *s; 2414 char_u *p; 2415 int fi; 2416 qfline_T *prevp = NULL; 2417 long lnum; 2418 buf_T *buf; 2419 int duplicate_name = FALSE; 2420 int using_dummy; 2421 int found_match; 2422 buf_T *first_match_buf = NULL; 2423 time_t seconds = 0; 2424 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 2425 char_u *save_ei = NULL; 2426 aco_save_T aco; 2427 #endif 2428 #ifdef FEAT_AUTOCMD 2429 char_u *au_name = NULL; 2430 int flags = 0; 2431 colnr_T col; 2432 2433 switch (eap->cmdidx) 2434 { 2435 case CMD_vimgrep: au_name = (char_u *)"vimgrep"; break; 2436 case CMD_vimgrepadd: au_name = (char_u *)"vimgrepadd"; break; 2437 default: break; 2438 } 2439 if (au_name != NULL) 2440 { 2441 apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, 2442 curbuf->b_fname, TRUE, curbuf); 2443 if (did_throw || force_abort) 2444 return; 2445 } 2446 #endif 2447 2448 /* Get the search pattern: either white-separated or enclosed in // */ 2449 regmatch.regprog = NULL; 2450 p = skip_vimgrep_pat(eap->arg, &s, &flags); 2451 if (p == NULL) 2452 { 2453 EMSG(_(e_invalpat)); 2454 goto theend; 2455 } 2456 regmatch.regprog = vim_regcomp(s, RE_MAGIC); 2457 if (regmatch.regprog == NULL) 2458 goto theend; 2459 regmatch.rmm_ic = p_ic; 2460 regmatch.rmm_maxcol = 0; 2461 2462 p = skipwhite(p); 2463 if (*p == NUL) 2464 { 2465 EMSG(_("E683: File name missing or invalid pattern")); 2466 goto theend; 2467 } 2468 2469 if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_vimgrepadd) 2470 || qf_curlist == qf_listcount) 2471 /* make place for a new list */ 2472 qf_new_list(); 2473 else if (qf_lists[qf_curlist].qf_count > 0) 2474 /* Adding to existing list, find last entry. */ 2475 for (prevp = qf_lists[qf_curlist].qf_start; 2476 prevp->qf_next != prevp; prevp = prevp->qf_next) 2477 ; 2478 2479 /* parse the list of arguments */ 2480 if (get_arglist_exp(p, &fcount, &fnames) == FAIL) 2481 goto theend; 2482 if (fcount == 0) 2483 { 2484 EMSG(_(e_nomatch)); 2485 goto theend; 2486 } 2487 2488 seconds = (time_t)0; 2489 for (fi = 0; fi < fcount && !got_int; ++fi) 2490 { 2491 if (time(NULL) > seconds) 2492 { 2493 /* Display the file name every second or so. */ 2494 seconds = time(NULL); 2495 msg_start(); 2496 p = msg_strtrunc(fnames[fi], TRUE); 2497 if (p == NULL) 2498 msg_outtrans(fnames[fi]); 2499 else 2500 { 2501 msg_outtrans(p); 2502 vim_free(p); 2503 } 2504 msg_clr_eos(); 2505 msg_didout = FALSE; /* overwrite this message */ 2506 msg_nowait = TRUE; /* don't wait for this message */ 2507 msg_col = 0; 2508 out_flush(); 2509 } 2510 2511 buf = buflist_findname_exp(fnames[fi]); 2512 if (buf == NULL || buf->b_ml.ml_mfp == NULL) 2513 { 2514 /* Remember that a buffer with this name already exists. */ 2515 duplicate_name = (buf != NULL); 2516 using_dummy = TRUE; 2517 2518 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 2519 /* Don't do Filetype autocommands to avoid loading syntax and 2520 * indent scripts, a great speed improvement. */ 2521 save_ei = au_event_disable(",Filetype"); 2522 #endif 2523 2524 /* Load file into a buffer, so that 'fileencoding' is detected, 2525 * autocommands applied, etc. */ 2526 buf = load_dummy_buffer(fnames[fi]); 2527 2528 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 2529 au_event_restore(save_ei); 2530 #endif 2531 } 2532 else 2533 /* Use existing, loaded buffer. */ 2534 using_dummy = FALSE; 2535 2536 if (buf == NULL) 2537 { 2538 if (!got_int) 2539 smsg((char_u *)_("Cannot open file \"%s\""), fnames[fi]); 2540 } 2541 else 2542 { 2543 found_match = FALSE; 2544 /* Try for a match in all lines of the buffer. */ 2545 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum) 2546 { 2547 /* For ":1vimgrep" look for multiple matches. */ 2548 col = 0; 2549 while (vim_regexec_multi(®match, curwin, buf, lnum, 2550 col) > 0) 2551 { 2552 if (qf_add_entry(&prevp, 2553 NULL, /* dir */ 2554 fnames[fi], 2555 ml_get_buf(buf, 2556 regmatch.startpos[0].lnum + lnum, FALSE), 2557 regmatch.startpos[0].lnum + lnum, 2558 regmatch.startpos[0].col + 1, 2559 FALSE, /* vis_col */ 2560 NULL, /* search pattern */ 2561 0, /* nr */ 2562 0, /* type */ 2563 TRUE /* valid */ 2564 ) == FAIL) 2565 { 2566 got_int = TRUE; 2567 break; 2568 } 2569 else 2570 found_match = TRUE; 2571 if ((flags & VGR_GLOBAL) == 0 2572 || regmatch.endpos[0].lnum > 0) 2573 break; 2574 col = regmatch.endpos[0].col 2575 + (col == regmatch.endpos[0].col); 2576 if (col > STRLEN(ml_get_buf(buf, lnum, FALSE))) 2577 break; 2578 } 2579 line_breakcheck(); 2580 if (got_int) 2581 break; 2582 } 2583 2584 if (using_dummy) 2585 { 2586 if (found_match && first_match_buf == NULL) 2587 first_match_buf = buf; 2588 if (duplicate_name) 2589 { 2590 /* Never keep a dummy buffer if there is another buffer 2591 * with the same name. */ 2592 wipe_dummy_buffer(buf); 2593 buf = NULL; 2594 } 2595 else if (!buf_hide(buf)) 2596 { 2597 /* When not hiding the buffer and no match was found we 2598 * don't need to remember the buffer, wipe it out. If 2599 * there was a match and it wasn't the first one or we 2600 * won't jump there: only unload the buffer. */ 2601 if (!found_match) 2602 { 2603 wipe_dummy_buffer(buf); 2604 buf = NULL; 2605 } 2606 else if (buf != first_match_buf || (flags & VGR_NOJUMP)) 2607 { 2608 unload_dummy_buffer(buf); 2609 buf = NULL; 2610 } 2611 } 2612 2613 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 2614 if (buf != NULL) 2615 { 2616 /* The buffer is still loaded, the Filetype autocommands 2617 * need to be done now, in that buffer. And then the 2618 * modelines need to be done (again). */ 2619 aucmd_prepbuf(&aco, buf); 2620 apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, 2621 buf->b_fname, TRUE, buf); 2622 do_modelines(FALSE); 2623 aucmd_restbuf(&aco); 2624 } 2625 #endif 2626 } 2627 } 2628 } 2629 2630 FreeWild(fcount, fnames); 2631 2632 qf_lists[qf_curlist].qf_nonevalid = FALSE; 2633 qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start; 2634 qf_lists[qf_curlist].qf_index = 1; 2635 2636 #ifdef FEAT_WINDOWS 2637 qf_update_buffer(); 2638 #endif 2639 2640 /* Jump to first match. */ 2641 if (qf_lists[qf_curlist].qf_count > 0) 2642 { 2643 if ((flags & VGR_NOJUMP) == 0) 2644 qf_jump(0, 0, eap->forceit); 2645 } 2646 else 2647 EMSG2(_(e_nomatch2), s); 2648 2649 #ifdef FEAT_AUTOCMD 2650 if (au_name != NULL) 2651 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, 2652 curbuf->b_fname, TRUE, curbuf); 2653 #endif 2654 2655 theend: 2656 vim_free(regmatch.regprog); 2657 } 2658 2659 /* 2660 * Skip over the pattern argument of ":vimgrep /pat/[g][j]". 2661 * Put the start of the pattern in "*s", unless "s" is NULL. 2662 * If "flags" is not NULL put the flags in it: VGR_GLOBAL, VGR_NOJUMP. 2663 * If "s" is not NULL terminate the pattern with a NUL. 2664 * Return a pointer to the char just past the pattern plus flags. 2665 */ 2666 char_u * 2667 skip_vimgrep_pat(p, s, flags) 2668 char_u *p; 2669 char_u **s; 2670 int *flags; 2671 { 2672 int c; 2673 2674 if (vim_isIDc(*p)) 2675 { 2676 /* ":vimgrep pattern fname" */ 2677 if (s != NULL) 2678 *s = p; 2679 p = skiptowhite(p); 2680 if (s != NULL && *p != NUL) 2681 *p++ = NUL; 2682 } 2683 else 2684 { 2685 /* ":vimgrep /pattern/[g][j] fname" */ 2686 if (s != NULL) 2687 *s = p + 1; 2688 c = *p; 2689 p = skip_regexp(p + 1, c, TRUE, NULL); 2690 if (*p != c) 2691 return NULL; 2692 2693 /* Truncate the pattern. */ 2694 if (s != NULL) 2695 *p = NUL; 2696 ++p; 2697 2698 /* Find the flags */ 2699 while (*p == 'g' || *p == 'j') 2700 { 2701 if (flags != NULL) 2702 { 2703 if (*p == 'g') 2704 *flags |= VGR_GLOBAL; 2705 else 2706 *flags |= VGR_NOJUMP; 2707 } 2708 ++p; 2709 } 2710 } 2711 return p; 2712 } 2713 2714 /* 2715 * Load file "fname" into a dummy buffer and return the buffer pointer. 2716 * Returns NULL if it fails. 2717 * Must call unload_dummy_buffer() or wipe_dummy_buffer() later! 2718 */ 2719 static buf_T * 2720 load_dummy_buffer(fname) 2721 char_u *fname; 2722 { 2723 buf_T *newbuf; 2724 int failed = TRUE; 2725 #ifdef FEAT_AUTOCMD 2726 aco_save_T aco; 2727 #else 2728 buf_T *old_curbuf = curbuf; 2729 #endif 2730 2731 /* Allocate a buffer without putting it in the buffer list. */ 2732 newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY); 2733 if (newbuf == NULL) 2734 return NULL; 2735 2736 /* Init the options. */ 2737 buf_copy_options(newbuf, BCO_ENTER | BCO_NOHELP); 2738 2739 #ifdef FEAT_AUTOCMD 2740 /* set curwin/curbuf to buf and save a few things */ 2741 aucmd_prepbuf(&aco, newbuf); 2742 #else 2743 curbuf = newbuf; 2744 curwin->w_buffer = newbuf; 2745 #endif 2746 2747 /* Need to set the filename for autocommands. */ 2748 (void)setfname(curbuf, fname, NULL, FALSE); 2749 2750 if (ml_open() == OK) 2751 { 2752 /* Create swap file now to avoid the ATTENTION message. */ 2753 check_need_swap(TRUE); 2754 2755 /* Remove the "dummy" flag, otherwise autocommands may not 2756 * work. */ 2757 curbuf->b_flags &= ~BF_DUMMY; 2758 2759 if (readfile(fname, NULL, 2760 (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, 2761 NULL, READ_NEW | READ_DUMMY) == OK 2762 && !(curbuf->b_flags & BF_NEW)) 2763 { 2764 failed = FALSE; 2765 if (curbuf != newbuf) 2766 { 2767 /* Bloody autocommands changed the buffer! */ 2768 if (buf_valid(newbuf)) 2769 wipe_buffer(newbuf, FALSE); 2770 newbuf = curbuf; 2771 } 2772 } 2773 } 2774 2775 #ifdef FEAT_AUTOCMD 2776 /* restore curwin/curbuf and a few other things */ 2777 aucmd_restbuf(&aco); 2778 #else 2779 curbuf = old_curbuf; 2780 curwin->w_buffer = old_curbuf; 2781 #endif 2782 2783 if (!buf_valid(newbuf)) 2784 return NULL; 2785 if (failed) 2786 { 2787 wipe_dummy_buffer(newbuf); 2788 return NULL; 2789 } 2790 return newbuf; 2791 } 2792 2793 /* 2794 * Wipe out the dummy buffer that load_dummy_buffer() created. 2795 */ 2796 static void 2797 wipe_dummy_buffer(buf) 2798 buf_T *buf; 2799 { 2800 if (curbuf != buf) /* safety check */ 2801 wipe_buffer(buf, FALSE); 2802 } 2803 2804 /* 2805 * Unload the dummy buffer that load_dummy_buffer() created. 2806 */ 2807 static void 2808 unload_dummy_buffer(buf) 2809 buf_T *buf; 2810 { 2811 if (curbuf != buf) /* safety check */ 2812 close_buffer(NULL, buf, DOBUF_UNLOAD); 2813 } 2814 2815 #if defined(FEAT_EVAL) || defined(PROTO) 2816 /* 2817 * Add each quickfix error to list "list" as a dictionary. 2818 */ 2819 int 2820 get_errorlist(list) 2821 list_T *list; 2822 { 2823 dict_T *dict; 2824 char_u buf[2]; 2825 qfline_T *qfp; 2826 int i; 2827 2828 if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0) 2829 return FAIL; 2830 2831 qfp = qf_lists[qf_curlist].qf_start; 2832 for (i = 1; !got_int && i <= qf_lists[qf_curlist].qf_count; ++i) 2833 { 2834 if ((dict = dict_alloc()) == NULL) 2835 return FAIL; 2836 if (list_append_dict(list, dict) == FAIL) 2837 return FAIL; 2838 2839 buf[0] = qfp->qf_type; 2840 buf[1] = NUL; 2841 if ( dict_add_nr_str(dict, "bufnr", (long)qfp->qf_fnum, NULL) == FAIL 2842 || dict_add_nr_str(dict, "lnum", (long)qfp->qf_lnum, NULL) == FAIL 2843 || dict_add_nr_str(dict, "col", (long)qfp->qf_col, NULL) == FAIL 2844 || dict_add_nr_str(dict, "vcol", (long)qfp->qf_viscol, NULL) == FAIL 2845 || dict_add_nr_str(dict, "nr", (long)qfp->qf_nr, NULL) == FAIL 2846 || dict_add_nr_str(dict, "pattern", 0L, qfp->qf_pattern) == FAIL 2847 || dict_add_nr_str(dict, "text", 0L, qfp->qf_text) == FAIL 2848 || dict_add_nr_str(dict, "type", 0L, buf) == FAIL 2849 || dict_add_nr_str(dict, "valid", (long)qfp->qf_valid, NULL) == FAIL) 2850 return FAIL; 2851 2852 qfp = qfp->qf_next; 2853 } 2854 return OK; 2855 } 2856 2857 /* 2858 * Populate the quickfix list with the items supplied in the list 2859 * of dictionaries. 2860 */ 2861 int 2862 set_errorlist(list, action) 2863 list_T *list; 2864 int action; 2865 { 2866 listitem_T *li; 2867 dict_T *d; 2868 char_u *filename, *pattern, *text, *type; 2869 long lnum; 2870 int col, nr; 2871 int vcol; 2872 qfline_T *prevp = NULL; 2873 int valid, status; 2874 int retval = OK; 2875 2876 if (action == ' ' || qf_curlist == qf_listcount) 2877 /* make place for a new list */ 2878 qf_new_list(); 2879 else if (action == 'a' && qf_lists[qf_curlist].qf_count > 0) 2880 /* Adding to existing list, find last entry. */ 2881 for (prevp = qf_lists[qf_curlist].qf_start; 2882 prevp->qf_next != prevp; prevp = prevp->qf_next) 2883 ; 2884 else if (action == 'r') 2885 qf_free(qf_curlist); 2886 2887 for (li = list->lv_first; li != NULL; li = li->li_next) 2888 { 2889 if (li->li_tv.v_type != VAR_DICT) 2890 continue; /* Skip non-dict items */ 2891 2892 d = li->li_tv.vval.v_dict; 2893 if (d == NULL) 2894 continue; 2895 2896 filename = get_dict_string(d, (char_u *)"filename"); 2897 lnum = get_dict_number(d, (char_u *)"lnum"); 2898 col = get_dict_number(d, (char_u *)"col"); 2899 vcol = get_dict_number(d, (char_u *)"vcol"); 2900 nr = get_dict_number(d, (char_u *)"nr"); 2901 type = get_dict_string(d, (char_u *)"type"); 2902 pattern = get_dict_string(d, (char_u *)"pattern"); 2903 text = get_dict_string(d, (char_u *)"text"); 2904 if (text == NULL) 2905 text = vim_strsave((char_u *)""); 2906 2907 valid = TRUE; 2908 if (filename == NULL || (lnum == 0 && pattern == NULL)) 2909 valid = FALSE; 2910 2911 status = qf_add_entry(&prevp, 2912 NULL, /* dir */ 2913 filename, 2914 text, 2915 lnum, 2916 col, 2917 vcol, /* vis_col */ 2918 pattern, /* search pattern */ 2919 nr, 2920 type == NULL ? NUL : *type, 2921 valid); 2922 2923 vim_free(filename); 2924 vim_free(pattern); 2925 vim_free(text); 2926 vim_free(type); 2927 2928 if (status == FAIL) 2929 { 2930 retval = FAIL; 2931 break; 2932 } 2933 } 2934 2935 qf_lists[qf_curlist].qf_nonevalid = FALSE; 2936 qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start; 2937 qf_lists[qf_curlist].qf_index = 1; 2938 2939 #ifdef FEAT_WINDOWS 2940 qf_update_buffer(); 2941 #endif 2942 2943 return retval; 2944 } 2945 #endif 2946 2947 /* 2948 * ":[range]cbuffer [bufnr]" command. 2949 */ 2950 void 2951 ex_cbuffer(eap) 2952 exarg_T *eap; 2953 { 2954 buf_T *buf = NULL; 2955 2956 if (*eap->arg == NUL) 2957 buf = curbuf; 2958 else if (*skipwhite(skipdigits(eap->arg)) == NUL) 2959 buf = buflist_findnr(atoi((char *)eap->arg)); 2960 if (buf == NULL) 2961 EMSG(_(e_invarg)); 2962 else if (buf->b_ml.ml_mfp == NULL) 2963 EMSG(_("E681: Buffer is not loaded")); 2964 else 2965 { 2966 if (eap->addr_count == 0) 2967 { 2968 eap->line1 = 1; 2969 eap->line2 = buf->b_ml.ml_line_count; 2970 } 2971 if (eap->line1 < 1 || eap->line1 > buf->b_ml.ml_line_count 2972 || eap->line2 < 1 || eap->line2 > buf->b_ml.ml_line_count) 2973 EMSG(_(e_invrange)); 2974 else 2975 qf_init_ext(NULL, buf, NULL, p_efm, TRUE, eap->line1, eap->line2); 2976 } 2977 } 2978 2979 #if defined(FEAT_EVAL) || defined(PROTO) 2980 /* 2981 * ":cexpr {expr}" command. 2982 */ 2983 void 2984 ex_cexpr(eap) 2985 exarg_T *eap; 2986 { 2987 typval_T *tv; 2988 2989 tv = eval_expr(eap->arg, NULL); 2990 if (!tv || (tv->v_type != VAR_STRING && tv->v_type != VAR_LIST) || 2991 (tv->v_type == VAR_STRING && !tv->vval.v_string) || 2992 (tv->v_type == VAR_LIST && !tv->vval.v_list)) 2993 return; 2994 2995 if (qf_init_ext(NULL, NULL, tv, p_efm, TRUE, (linenr_T)0, (linenr_T)0) > 0) 2996 qf_jump(0, 0, eap->forceit); /* display first error */ 2997 2998 clear_tv(tv); 2999 } 3000 #endif 3001 3002 /* 3003 * ":helpgrep {pattern}" 3004 */ 3005 void 3006 ex_helpgrep(eap) 3007 exarg_T *eap; 3008 { 3009 regmatch_T regmatch; 3010 char_u *save_cpo; 3011 char_u *p; 3012 int fcount; 3013 char_u **fnames; 3014 FILE *fd; 3015 int fi; 3016 qfline_T *prevp = NULL; 3017 long lnum; 3018 #ifdef FEAT_MULTI_LANG 3019 char_u *lang; 3020 #endif 3021 3022 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ 3023 save_cpo = p_cpo; 3024 p_cpo = (char_u *)""; 3025 3026 #ifdef FEAT_MULTI_LANG 3027 /* Check for a specified language */ 3028 lang = check_help_lang(eap->arg); 3029 #endif 3030 3031 regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING); 3032 regmatch.rm_ic = FALSE; 3033 if (regmatch.regprog != NULL) 3034 { 3035 /* create a new quickfix list */ 3036 qf_new_list(); 3037 3038 /* Go through all directories in 'runtimepath' */ 3039 p = p_rtp; 3040 while (*p != NUL && !got_int) 3041 { 3042 copy_option_part(&p, NameBuff, MAXPATHL, ","); 3043 3044 /* Find all "*.txt" and "*.??x" files in the "doc" directory. */ 3045 add_pathsep(NameBuff); 3046 STRCAT(NameBuff, "doc/*.\\(txt\\|??x\\)"); 3047 if (gen_expand_wildcards(1, &NameBuff, &fcount, 3048 &fnames, EW_FILE|EW_SILENT) == OK 3049 && fcount > 0) 3050 { 3051 for (fi = 0; fi < fcount && !got_int; ++fi) 3052 { 3053 #ifdef FEAT_MULTI_LANG 3054 /* Skip files for a different language. */ 3055 if (lang != NULL 3056 && STRNICMP(lang, fnames[fi] 3057 + STRLEN(fnames[fi]) - 3, 2) != 0 3058 && !(STRNICMP(lang, "en", 2) == 0 3059 && STRNICMP("txt", fnames[fi] 3060 + STRLEN(fnames[fi]) - 3, 3) == 0)) 3061 continue; 3062 #endif 3063 fd = mch_fopen((char *)fnames[fi], "r"); 3064 if (fd != NULL) 3065 { 3066 lnum = 1; 3067 while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) 3068 { 3069 if (vim_regexec(®match, IObuff, (colnr_T)0)) 3070 { 3071 int l = STRLEN(IObuff); 3072 3073 /* remove trailing CR, LF, spaces, etc. */ 3074 while (l > 0 && IObuff[l - 1] <= ' ') 3075 IObuff[--l] = NUL; 3076 3077 if (qf_add_entry(&prevp, 3078 NULL, /* dir */ 3079 fnames[fi], 3080 IObuff, 3081 lnum, 3082 (int)(regmatch.startp[0] - IObuff) 3083 + 1, /* col */ 3084 FALSE, /* vis_col */ 3085 NULL, /* search pattern */ 3086 0, /* nr */ 3087 1, /* type */ 3088 TRUE /* valid */ 3089 ) == FAIL) 3090 { 3091 got_int = TRUE; 3092 break; 3093 } 3094 } 3095 ++lnum; 3096 line_breakcheck(); 3097 } 3098 fclose(fd); 3099 } 3100 } 3101 FreeWild(fcount, fnames); 3102 } 3103 } 3104 vim_free(regmatch.regprog); 3105 3106 qf_lists[qf_curlist].qf_nonevalid = FALSE; 3107 qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start; 3108 qf_lists[qf_curlist].qf_index = 1; 3109 } 3110 3111 p_cpo = save_cpo; 3112 3113 #ifdef FEAT_WINDOWS 3114 qf_update_buffer(); 3115 #endif 3116 3117 /* Jump to first match. */ 3118 if (qf_lists[qf_curlist].qf_count > 0) 3119 qf_jump(0, 0, FALSE); 3120 else 3121 EMSG2(_(e_nomatch2), eap->arg); 3122 } 3123 3124 #endif /* FEAT_QUICKFIX */ 3125