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