1 /* vi:set ts=8 sts=4 sw=4 noet: 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 * misc1.c: functions that didn't seem to fit elsewhere 12 */ 13 14 #include "vim.h" 15 #include "version.h" 16 17 static char_u *vim_version_dir(char_u *vimdir); 18 static char_u *remove_tail(char_u *p, char_u *pend, char_u *name); 19 #if defined(FEAT_CMDL_COMPL) 20 static void init_users(void); 21 #endif 22 static int copy_indent(int size, char_u *src); 23 24 /* All user names (for ~user completion as done by shell). */ 25 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 26 static garray_T ga_users; 27 #endif 28 29 /* 30 * Count the size (in window cells) of the indent in the current line. 31 */ 32 int 33 get_indent(void) 34 { 35 return get_indent_str(ml_get_curline(), (int)curbuf->b_p_ts, FALSE); 36 } 37 38 /* 39 * Count the size (in window cells) of the indent in line "lnum". 40 */ 41 int 42 get_indent_lnum(linenr_T lnum) 43 { 44 return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts, FALSE); 45 } 46 47 #if defined(FEAT_FOLDING) || defined(PROTO) 48 /* 49 * Count the size (in window cells) of the indent in line "lnum" of buffer 50 * "buf". 51 */ 52 int 53 get_indent_buf(buf_T *buf, linenr_T lnum) 54 { 55 return get_indent_str(ml_get_buf(buf, lnum, FALSE), (int)buf->b_p_ts, FALSE); 56 } 57 #endif 58 59 /* 60 * count the size (in window cells) of the indent in line "ptr", with 61 * 'tabstop' at "ts" 62 */ 63 int 64 get_indent_str( 65 char_u *ptr, 66 int ts, 67 int list) /* if TRUE, count only screen size for tabs */ 68 { 69 int count = 0; 70 71 for ( ; *ptr; ++ptr) 72 { 73 if (*ptr == TAB) 74 { 75 if (!list || lcs_tab1) /* count a tab for what it is worth */ 76 count += ts - (count % ts); 77 else 78 /* In list mode, when tab is not set, count screen char width 79 * for Tab, displays: ^I */ 80 count += ptr2cells(ptr); 81 } 82 else if (*ptr == ' ') 83 ++count; /* count a space for one */ 84 else 85 break; 86 } 87 return count; 88 } 89 90 /* 91 * Set the indent of the current line. 92 * Leaves the cursor on the first non-blank in the line. 93 * Caller must take care of undo. 94 * "flags": 95 * SIN_CHANGED: call changed_bytes() if the line was changed. 96 * SIN_INSERT: insert the indent in front of the line. 97 * SIN_UNDO: save line for undo before changing it. 98 * Returns TRUE if the line was changed. 99 */ 100 int 101 set_indent( 102 int size, /* measured in spaces */ 103 int flags) 104 { 105 char_u *p; 106 char_u *newline; 107 char_u *oldline; 108 char_u *s; 109 int todo; 110 int ind_len; /* measured in characters */ 111 int line_len; 112 int doit = FALSE; 113 int ind_done = 0; /* measured in spaces */ 114 int tab_pad; 115 int retval = FALSE; 116 int orig_char_len = -1; /* number of initial whitespace chars when 117 'et' and 'pi' are both set */ 118 119 /* 120 * First check if there is anything to do and compute the number of 121 * characters needed for the indent. 122 */ 123 todo = size; 124 ind_len = 0; 125 p = oldline = ml_get_curline(); 126 127 /* Calculate the buffer size for the new indent, and check to see if it 128 * isn't already set */ 129 130 /* if 'expandtab' isn't set: use TABs; if both 'expandtab' and 131 * 'preserveindent' are set count the number of characters at the 132 * beginning of the line to be copied */ 133 if (!curbuf->b_p_et || (!(flags & SIN_INSERT) && curbuf->b_p_pi)) 134 { 135 /* If 'preserveindent' is set then reuse as much as possible of 136 * the existing indent structure for the new indent */ 137 if (!(flags & SIN_INSERT) && curbuf->b_p_pi) 138 { 139 ind_done = 0; 140 141 /* count as many characters as we can use */ 142 while (todo > 0 && VIM_ISWHITE(*p)) 143 { 144 if (*p == TAB) 145 { 146 tab_pad = (int)curbuf->b_p_ts 147 - (ind_done % (int)curbuf->b_p_ts); 148 /* stop if this tab will overshoot the target */ 149 if (todo < tab_pad) 150 break; 151 todo -= tab_pad; 152 ++ind_len; 153 ind_done += tab_pad; 154 } 155 else 156 { 157 --todo; 158 ++ind_len; 159 ++ind_done; 160 } 161 ++p; 162 } 163 164 /* Set initial number of whitespace chars to copy if we are 165 * preserving indent but expandtab is set */ 166 if (curbuf->b_p_et) 167 orig_char_len = ind_len; 168 169 /* Fill to next tabstop with a tab, if possible */ 170 tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); 171 if (todo >= tab_pad && orig_char_len == -1) 172 { 173 doit = TRUE; 174 todo -= tab_pad; 175 ++ind_len; 176 /* ind_done += tab_pad; */ 177 } 178 } 179 180 /* count tabs required for indent */ 181 while (todo >= (int)curbuf->b_p_ts) 182 { 183 if (*p != TAB) 184 doit = TRUE; 185 else 186 ++p; 187 todo -= (int)curbuf->b_p_ts; 188 ++ind_len; 189 /* ind_done += (int)curbuf->b_p_ts; */ 190 } 191 } 192 /* count spaces required for indent */ 193 while (todo > 0) 194 { 195 if (*p != ' ') 196 doit = TRUE; 197 else 198 ++p; 199 --todo; 200 ++ind_len; 201 /* ++ind_done; */ 202 } 203 204 /* Return if the indent is OK already. */ 205 if (!doit && !VIM_ISWHITE(*p) && !(flags & SIN_INSERT)) 206 return FALSE; 207 208 /* Allocate memory for the new line. */ 209 if (flags & SIN_INSERT) 210 p = oldline; 211 else 212 p = skipwhite(p); 213 line_len = (int)STRLEN(p) + 1; 214 215 /* If 'preserveindent' and 'expandtab' are both set keep the original 216 * characters and allocate accordingly. We will fill the rest with spaces 217 * after the if (!curbuf->b_p_et) below. */ 218 if (orig_char_len != -1) 219 { 220 newline = alloc(orig_char_len + size - ind_done + line_len); 221 if (newline == NULL) 222 return FALSE; 223 todo = size - ind_done; 224 ind_len = orig_char_len + todo; /* Set total length of indent in 225 * characters, which may have been 226 * undercounted until now */ 227 p = oldline; 228 s = newline; 229 while (orig_char_len > 0) 230 { 231 *s++ = *p++; 232 orig_char_len--; 233 } 234 235 /* Skip over any additional white space (useful when newindent is less 236 * than old) */ 237 while (VIM_ISWHITE(*p)) 238 ++p; 239 240 } 241 else 242 { 243 todo = size; 244 newline = alloc(ind_len + line_len); 245 if (newline == NULL) 246 return FALSE; 247 s = newline; 248 } 249 250 /* Put the characters in the new line. */ 251 /* if 'expandtab' isn't set: use TABs */ 252 if (!curbuf->b_p_et) 253 { 254 /* If 'preserveindent' is set then reuse as much as possible of 255 * the existing indent structure for the new indent */ 256 if (!(flags & SIN_INSERT) && curbuf->b_p_pi) 257 { 258 p = oldline; 259 ind_done = 0; 260 261 while (todo > 0 && VIM_ISWHITE(*p)) 262 { 263 if (*p == TAB) 264 { 265 tab_pad = (int)curbuf->b_p_ts 266 - (ind_done % (int)curbuf->b_p_ts); 267 /* stop if this tab will overshoot the target */ 268 if (todo < tab_pad) 269 break; 270 todo -= tab_pad; 271 ind_done += tab_pad; 272 } 273 else 274 { 275 --todo; 276 ++ind_done; 277 } 278 *s++ = *p++; 279 } 280 281 /* Fill to next tabstop with a tab, if possible */ 282 tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); 283 if (todo >= tab_pad) 284 { 285 *s++ = TAB; 286 todo -= tab_pad; 287 } 288 289 p = skipwhite(p); 290 } 291 292 while (todo >= (int)curbuf->b_p_ts) 293 { 294 *s++ = TAB; 295 todo -= (int)curbuf->b_p_ts; 296 } 297 } 298 while (todo > 0) 299 { 300 *s++ = ' '; 301 --todo; 302 } 303 mch_memmove(s, p, (size_t)line_len); 304 305 /* Replace the line (unless undo fails). */ 306 if (!(flags & SIN_UNDO) || u_savesub(curwin->w_cursor.lnum) == OK) 307 { 308 ml_replace(curwin->w_cursor.lnum, newline, FALSE); 309 if (flags & SIN_CHANGED) 310 changed_bytes(curwin->w_cursor.lnum, 0); 311 /* Correct saved cursor position if it is in this line. */ 312 if (saved_cursor.lnum == curwin->w_cursor.lnum) 313 { 314 if (saved_cursor.col >= (colnr_T)(p - oldline)) 315 /* cursor was after the indent, adjust for the number of 316 * bytes added/removed */ 317 saved_cursor.col += ind_len - (colnr_T)(p - oldline); 318 else if (saved_cursor.col >= (colnr_T)(s - newline)) 319 /* cursor was in the indent, and is now after it, put it back 320 * at the start of the indent (replacing spaces with TAB) */ 321 saved_cursor.col = (colnr_T)(s - newline); 322 } 323 retval = TRUE; 324 } 325 else 326 vim_free(newline); 327 328 curwin->w_cursor.col = ind_len; 329 return retval; 330 } 331 332 /* 333 * Copy the indent from ptr to the current line (and fill to size) 334 * Leaves the cursor on the first non-blank in the line. 335 * Returns TRUE if the line was changed. 336 */ 337 static int 338 copy_indent(int size, char_u *src) 339 { 340 char_u *p = NULL; 341 char_u *line = NULL; 342 char_u *s; 343 int todo; 344 int ind_len; 345 int line_len = 0; 346 int tab_pad; 347 int ind_done; 348 int round; 349 350 /* Round 1: compute the number of characters needed for the indent 351 * Round 2: copy the characters. */ 352 for (round = 1; round <= 2; ++round) 353 { 354 todo = size; 355 ind_len = 0; 356 ind_done = 0; 357 s = src; 358 359 /* Count/copy the usable portion of the source line */ 360 while (todo > 0 && VIM_ISWHITE(*s)) 361 { 362 if (*s == TAB) 363 { 364 tab_pad = (int)curbuf->b_p_ts 365 - (ind_done % (int)curbuf->b_p_ts); 366 /* Stop if this tab will overshoot the target */ 367 if (todo < tab_pad) 368 break; 369 todo -= tab_pad; 370 ind_done += tab_pad; 371 } 372 else 373 { 374 --todo; 375 ++ind_done; 376 } 377 ++ind_len; 378 if (p != NULL) 379 *p++ = *s; 380 ++s; 381 } 382 383 /* Fill to next tabstop with a tab, if possible */ 384 tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); 385 if (todo >= tab_pad && !curbuf->b_p_et) 386 { 387 todo -= tab_pad; 388 ++ind_len; 389 if (p != NULL) 390 *p++ = TAB; 391 } 392 393 /* Add tabs required for indent */ 394 while (todo >= (int)curbuf->b_p_ts && !curbuf->b_p_et) 395 { 396 todo -= (int)curbuf->b_p_ts; 397 ++ind_len; 398 if (p != NULL) 399 *p++ = TAB; 400 } 401 402 /* Count/add spaces required for indent */ 403 while (todo > 0) 404 { 405 --todo; 406 ++ind_len; 407 if (p != NULL) 408 *p++ = ' '; 409 } 410 411 if (p == NULL) 412 { 413 /* Allocate memory for the result: the copied indent, new indent 414 * and the rest of the line. */ 415 line_len = (int)STRLEN(ml_get_curline()) + 1; 416 line = alloc(ind_len + line_len); 417 if (line == NULL) 418 return FALSE; 419 p = line; 420 } 421 } 422 423 /* Append the original line */ 424 mch_memmove(p, ml_get_curline(), (size_t)line_len); 425 426 /* Replace the line */ 427 ml_replace(curwin->w_cursor.lnum, line, FALSE); 428 429 /* Put the cursor after the indent. */ 430 curwin->w_cursor.col = ind_len; 431 return TRUE; 432 } 433 434 /* 435 * Return the indent of the current line after a number. Return -1 if no 436 * number was found. Used for 'n' in 'formatoptions': numbered list. 437 * Since a pattern is used it can actually handle more than numbers. 438 */ 439 int 440 get_number_indent(linenr_T lnum) 441 { 442 colnr_T col; 443 pos_T pos; 444 445 regmatch_T regmatch; 446 int lead_len = 0; /* length of comment leader */ 447 448 if (lnum > curbuf->b_ml.ml_line_count) 449 return -1; 450 pos.lnum = 0; 451 452 #ifdef FEAT_COMMENTS 453 /* In format_lines() (i.e. not insert mode), fo+=q is needed too... */ 454 if ((State & INSERT) || has_format_option(FO_Q_COMS)) 455 lead_len = get_leader_len(ml_get(lnum), NULL, FALSE, TRUE); 456 #endif 457 regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC); 458 if (regmatch.regprog != NULL) 459 { 460 regmatch.rm_ic = FALSE; 461 462 /* vim_regexec() expects a pointer to a line. This lets us 463 * start matching for the flp beyond any comment leader... */ 464 if (vim_regexec(®match, ml_get(lnum) + lead_len, (colnr_T)0)) 465 { 466 pos.lnum = lnum; 467 pos.col = (colnr_T)(*regmatch.endp - ml_get(lnum)); 468 #ifdef FEAT_VIRTUALEDIT 469 pos.coladd = 0; 470 #endif 471 } 472 vim_regfree(regmatch.regprog); 473 } 474 475 if (pos.lnum == 0 || *ml_get_pos(&pos) == NUL) 476 return -1; 477 getvcol(curwin, &pos, &col, NULL, NULL); 478 return (int)col; 479 } 480 481 #if defined(FEAT_LINEBREAK) || defined(PROTO) 482 /* 483 * Return appropriate space number for breakindent, taking influencing 484 * parameters into account. Window must be specified, since it is not 485 * necessarily always the current one. 486 */ 487 int 488 get_breakindent_win( 489 win_T *wp, 490 char_u *line) /* start of the line */ 491 { 492 static int prev_indent = 0; /* cached indent value */ 493 static long prev_ts = 0L; /* cached tabstop value */ 494 static char_u *prev_line = NULL; /* cached pointer to line */ 495 static varnumber_T prev_tick = 0; /* changedtick of cached value */ 496 int bri = 0; 497 /* window width minus window margin space, i.e. what rests for text */ 498 const int eff_wwidth = W_WIDTH(wp) 499 - ((wp->w_p_nu || wp->w_p_rnu) 500 && (vim_strchr(p_cpo, CPO_NUMCOL) == NULL) 501 ? number_width(wp) + 1 : 0); 502 503 /* used cached indent, unless pointer or 'tabstop' changed */ 504 if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts 505 || prev_tick != CHANGEDTICK(wp->w_buffer)) 506 { 507 prev_line = line; 508 prev_ts = wp->w_buffer->b_p_ts; 509 prev_tick = CHANGEDTICK(wp->w_buffer); 510 prev_indent = get_indent_str(line, 511 (int)wp->w_buffer->b_p_ts, wp->w_p_list); 512 } 513 bri = prev_indent + wp->w_p_brishift; 514 515 /* indent minus the length of the showbreak string */ 516 if (wp->w_p_brisbr) 517 bri -= vim_strsize(p_sbr); 518 519 /* Add offset for number column, if 'n' is in 'cpoptions' */ 520 bri += win_col_off2(wp); 521 522 /* never indent past left window margin */ 523 if (bri < 0) 524 bri = 0; 525 /* always leave at least bri_min characters on the left, 526 * if text width is sufficient */ 527 else if (bri > eff_wwidth - wp->w_p_brimin) 528 bri = (eff_wwidth - wp->w_p_brimin < 0) 529 ? 0 : eff_wwidth - wp->w_p_brimin; 530 531 return bri; 532 } 533 #endif 534 535 536 #if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT) 537 538 static int cin_is_cinword(char_u *line); 539 540 /* 541 * Return TRUE if the string "line" starts with a word from 'cinwords'. 542 */ 543 static int 544 cin_is_cinword(char_u *line) 545 { 546 char_u *cinw; 547 char_u *cinw_buf; 548 int cinw_len; 549 int retval = FALSE; 550 int len; 551 552 cinw_len = (int)STRLEN(curbuf->b_p_cinw) + 1; 553 cinw_buf = alloc((unsigned)cinw_len); 554 if (cinw_buf != NULL) 555 { 556 line = skipwhite(line); 557 for (cinw = curbuf->b_p_cinw; *cinw; ) 558 { 559 len = copy_option_part(&cinw, cinw_buf, cinw_len, ","); 560 if (STRNCMP(line, cinw_buf, len) == 0 561 && (!vim_iswordc(line[len]) || !vim_iswordc(line[len - 1]))) 562 { 563 retval = TRUE; 564 break; 565 } 566 } 567 vim_free(cinw_buf); 568 } 569 return retval; 570 } 571 #endif 572 573 /* 574 * open_line: Add a new line below or above the current line. 575 * 576 * For VREPLACE mode, we only add a new line when we get to the end of the 577 * file, otherwise we just start replacing the next line. 578 * 579 * Caller must take care of undo. Since VREPLACE may affect any number of 580 * lines however, it may call u_save_cursor() again when starting to change a 581 * new line. 582 * "flags": OPENLINE_DELSPACES delete spaces after cursor 583 * OPENLINE_DO_COM format comments 584 * OPENLINE_KEEPTRAIL keep trailing spaces 585 * OPENLINE_MARKFIX adjust mark positions after the line break 586 * OPENLINE_COM_LIST format comments with list or 2nd line indent 587 * 588 * "second_line_indent": indent for after ^^D in Insert mode or if flag 589 * OPENLINE_COM_LIST 590 * 591 * Return TRUE for success, FALSE for failure 592 */ 593 int 594 open_line( 595 int dir, /* FORWARD or BACKWARD */ 596 int flags, 597 int second_line_indent) 598 { 599 char_u *saved_line; /* copy of the original line */ 600 char_u *next_line = NULL; /* copy of the next line */ 601 char_u *p_extra = NULL; /* what goes to next line */ 602 int less_cols = 0; /* less columns for mark in new line */ 603 int less_cols_off = 0; /* columns to skip for mark adjust */ 604 pos_T old_cursor; /* old cursor position */ 605 int newcol = 0; /* new cursor column */ 606 int newindent = 0; /* auto-indent of the new line */ 607 int n; 608 int trunc_line = FALSE; /* truncate current line afterwards */ 609 int retval = FALSE; /* return value, default is FAIL */ 610 #ifdef FEAT_COMMENTS 611 int extra_len = 0; /* length of p_extra string */ 612 int lead_len; /* length of comment leader */ 613 char_u *lead_flags; /* position in 'comments' for comment leader */ 614 char_u *leader = NULL; /* copy of comment leader */ 615 #endif 616 char_u *allocated = NULL; /* allocated memory */ 617 #if defined(FEAT_SMARTINDENT) || defined(FEAT_VREPLACE) || defined(FEAT_LISP) \ 618 || defined(FEAT_CINDENT) || defined(FEAT_COMMENTS) 619 char_u *p; 620 #endif 621 int saved_char = NUL; /* init for GCC */ 622 #if defined(FEAT_SMARTINDENT) || defined(FEAT_COMMENTS) 623 pos_T *pos; 624 #endif 625 #ifdef FEAT_SMARTINDENT 626 int do_si = (!p_paste && curbuf->b_p_si 627 # ifdef FEAT_CINDENT 628 && !curbuf->b_p_cin 629 # endif 630 ); 631 int no_si = FALSE; /* reset did_si afterwards */ 632 int first_char = NUL; /* init for GCC */ 633 #endif 634 #if defined(FEAT_VREPLACE) && (defined(FEAT_LISP) || defined(FEAT_CINDENT)) 635 int vreplace_mode; 636 #endif 637 int did_append; /* appended a new line */ 638 int saved_pi = curbuf->b_p_pi; /* copy of preserveindent setting */ 639 640 /* 641 * make a copy of the current line so we can mess with it 642 */ 643 saved_line = vim_strsave(ml_get_curline()); 644 if (saved_line == NULL) /* out of memory! */ 645 return FALSE; 646 647 #ifdef FEAT_VREPLACE 648 if (State & VREPLACE_FLAG) 649 { 650 /* 651 * With VREPLACE we make a copy of the next line, which we will be 652 * starting to replace. First make the new line empty and let vim play 653 * with the indenting and comment leader to its heart's content. Then 654 * we grab what it ended up putting on the new line, put back the 655 * original line, and call ins_char() to put each new character onto 656 * the line, replacing what was there before and pushing the right 657 * stuff onto the replace stack. -- webb. 658 */ 659 if (curwin->w_cursor.lnum < orig_line_count) 660 next_line = vim_strsave(ml_get(curwin->w_cursor.lnum + 1)); 661 else 662 next_line = vim_strsave((char_u *)""); 663 if (next_line == NULL) /* out of memory! */ 664 goto theend; 665 666 /* 667 * In VREPLACE mode, a NL replaces the rest of the line, and starts 668 * replacing the next line, so push all of the characters left on the 669 * line onto the replace stack. We'll push any other characters that 670 * might be replaced at the start of the next line (due to autoindent 671 * etc) a bit later. 672 */ 673 replace_push(NUL); /* Call twice because BS over NL expects it */ 674 replace_push(NUL); 675 p = saved_line + curwin->w_cursor.col; 676 while (*p != NUL) 677 { 678 #ifdef FEAT_MBYTE 679 if (has_mbyte) 680 p += replace_push_mb(p); 681 else 682 #endif 683 replace_push(*p++); 684 } 685 saved_line[curwin->w_cursor.col] = NUL; 686 } 687 #endif 688 689 if ((State & INSERT) 690 #ifdef FEAT_VREPLACE 691 && !(State & VREPLACE_FLAG) 692 #endif 693 ) 694 { 695 p_extra = saved_line + curwin->w_cursor.col; 696 #ifdef FEAT_SMARTINDENT 697 if (do_si) /* need first char after new line break */ 698 { 699 p = skipwhite(p_extra); 700 first_char = *p; 701 } 702 #endif 703 #ifdef FEAT_COMMENTS 704 extra_len = (int)STRLEN(p_extra); 705 #endif 706 saved_char = *p_extra; 707 *p_extra = NUL; 708 } 709 710 u_clearline(); /* cannot do "U" command when adding lines */ 711 #ifdef FEAT_SMARTINDENT 712 did_si = FALSE; 713 #endif 714 ai_col = 0; 715 716 /* 717 * If we just did an auto-indent, then we didn't type anything on 718 * the prior line, and it should be truncated. Do this even if 'ai' is not 719 * set because automatically inserting a comment leader also sets did_ai. 720 */ 721 if (dir == FORWARD && did_ai) 722 trunc_line = TRUE; 723 724 /* 725 * If 'autoindent' and/or 'smartindent' is set, try to figure out what 726 * indent to use for the new line. 727 */ 728 if (curbuf->b_p_ai 729 #ifdef FEAT_SMARTINDENT 730 || do_si 731 #endif 732 ) 733 { 734 /* 735 * count white space on current line 736 */ 737 newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, FALSE); 738 if (newindent == 0 && !(flags & OPENLINE_COM_LIST)) 739 newindent = second_line_indent; /* for ^^D command in insert mode */ 740 741 #ifdef FEAT_SMARTINDENT 742 /* 743 * Do smart indenting. 744 * In insert/replace mode (only when dir == FORWARD) 745 * we may move some text to the next line. If it starts with '{' 746 * don't add an indent. Fixes inserting a NL before '{' in line 747 * "if (condition) {" 748 */ 749 if (!trunc_line && do_si && *saved_line != NUL 750 && (p_extra == NULL || first_char != '{')) 751 { 752 char_u *ptr; 753 char_u last_char; 754 755 old_cursor = curwin->w_cursor; 756 ptr = saved_line; 757 # ifdef FEAT_COMMENTS 758 if (flags & OPENLINE_DO_COM) 759 lead_len = get_leader_len(ptr, NULL, FALSE, TRUE); 760 else 761 lead_len = 0; 762 # endif 763 if (dir == FORWARD) 764 { 765 /* 766 * Skip preprocessor directives, unless they are 767 * recognised as comments. 768 */ 769 if ( 770 # ifdef FEAT_COMMENTS 771 lead_len == 0 && 772 # endif 773 ptr[0] == '#') 774 { 775 while (ptr[0] == '#' && curwin->w_cursor.lnum > 1) 776 ptr = ml_get(--curwin->w_cursor.lnum); 777 newindent = get_indent(); 778 } 779 # ifdef FEAT_COMMENTS 780 if (flags & OPENLINE_DO_COM) 781 lead_len = get_leader_len(ptr, NULL, FALSE, TRUE); 782 else 783 lead_len = 0; 784 if (lead_len > 0) 785 { 786 /* 787 * This case gets the following right: 788 * \* 789 * * A comment (read '\' as '/'). 790 * *\ 791 * #define IN_THE_WAY 792 * This should line up here; 793 */ 794 p = skipwhite(ptr); 795 if (p[0] == '/' && p[1] == '*') 796 p++; 797 if (p[0] == '*') 798 { 799 for (p++; *p; p++) 800 { 801 if (p[0] == '/' && p[-1] == '*') 802 { 803 /* 804 * End of C comment, indent should line up 805 * with the line containing the start of 806 * the comment 807 */ 808 curwin->w_cursor.col = (colnr_T)(p - ptr); 809 if ((pos = findmatch(NULL, NUL)) != NULL) 810 { 811 curwin->w_cursor.lnum = pos->lnum; 812 newindent = get_indent(); 813 } 814 } 815 } 816 } 817 } 818 else /* Not a comment line */ 819 # endif 820 { 821 /* Find last non-blank in line */ 822 p = ptr + STRLEN(ptr) - 1; 823 while (p > ptr && VIM_ISWHITE(*p)) 824 --p; 825 last_char = *p; 826 827 /* 828 * find the character just before the '{' or ';' 829 */ 830 if (last_char == '{' || last_char == ';') 831 { 832 if (p > ptr) 833 --p; 834 while (p > ptr && VIM_ISWHITE(*p)) 835 --p; 836 } 837 /* 838 * Try to catch lines that are split over multiple 839 * lines. eg: 840 * if (condition && 841 * condition) { 842 * Should line up here! 843 * } 844 */ 845 if (*p == ')') 846 { 847 curwin->w_cursor.col = (colnr_T)(p - ptr); 848 if ((pos = findmatch(NULL, '(')) != NULL) 849 { 850 curwin->w_cursor.lnum = pos->lnum; 851 newindent = get_indent(); 852 ptr = ml_get_curline(); 853 } 854 } 855 /* 856 * If last character is '{' do indent, without 857 * checking for "if" and the like. 858 */ 859 if (last_char == '{') 860 { 861 did_si = TRUE; /* do indent */ 862 no_si = TRUE; /* don't delete it when '{' typed */ 863 } 864 /* 865 * Look for "if" and the like, use 'cinwords'. 866 * Don't do this if the previous line ended in ';' or 867 * '}'. 868 */ 869 else if (last_char != ';' && last_char != '}' 870 && cin_is_cinword(ptr)) 871 did_si = TRUE; 872 } 873 } 874 else /* dir == BACKWARD */ 875 { 876 /* 877 * Skip preprocessor directives, unless they are 878 * recognised as comments. 879 */ 880 if ( 881 # ifdef FEAT_COMMENTS 882 lead_len == 0 && 883 # endif 884 ptr[0] == '#') 885 { 886 int was_backslashed = FALSE; 887 888 while ((ptr[0] == '#' || was_backslashed) && 889 curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) 890 { 891 if (*ptr && ptr[STRLEN(ptr) - 1] == '\\') 892 was_backslashed = TRUE; 893 else 894 was_backslashed = FALSE; 895 ptr = ml_get(++curwin->w_cursor.lnum); 896 } 897 if (was_backslashed) 898 newindent = 0; /* Got to end of file */ 899 else 900 newindent = get_indent(); 901 } 902 p = skipwhite(ptr); 903 if (*p == '}') /* if line starts with '}': do indent */ 904 did_si = TRUE; 905 else /* can delete indent when '{' typed */ 906 can_si_back = TRUE; 907 } 908 curwin->w_cursor = old_cursor; 909 } 910 if (do_si) 911 can_si = TRUE; 912 #endif /* FEAT_SMARTINDENT */ 913 914 did_ai = TRUE; 915 } 916 917 #ifdef FEAT_COMMENTS 918 /* 919 * Find out if the current line starts with a comment leader. 920 * This may then be inserted in front of the new line. 921 */ 922 end_comment_pending = NUL; 923 if (flags & OPENLINE_DO_COM) 924 lead_len = get_leader_len(saved_line, &lead_flags, dir == BACKWARD, TRUE); 925 else 926 lead_len = 0; 927 if (lead_len > 0) 928 { 929 char_u *lead_repl = NULL; /* replaces comment leader */ 930 int lead_repl_len = 0; /* length of *lead_repl */ 931 char_u lead_middle[COM_MAX_LEN]; /* middle-comment string */ 932 char_u lead_end[COM_MAX_LEN]; /* end-comment string */ 933 char_u *comment_end = NULL; /* where lead_end has been found */ 934 int extra_space = FALSE; /* append extra space */ 935 int current_flag; 936 int require_blank = FALSE; /* requires blank after middle */ 937 char_u *p2; 938 939 /* 940 * If the comment leader has the start, middle or end flag, it may not 941 * be used or may be replaced with the middle leader. 942 */ 943 for (p = lead_flags; *p && *p != ':'; ++p) 944 { 945 if (*p == COM_BLANK) 946 { 947 require_blank = TRUE; 948 continue; 949 } 950 if (*p == COM_START || *p == COM_MIDDLE) 951 { 952 current_flag = *p; 953 if (*p == COM_START) 954 { 955 /* 956 * Doing "O" on a start of comment does not insert leader. 957 */ 958 if (dir == BACKWARD) 959 { 960 lead_len = 0; 961 break; 962 } 963 964 /* find start of middle part */ 965 (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ","); 966 require_blank = FALSE; 967 } 968 969 /* 970 * Isolate the strings of the middle and end leader. 971 */ 972 while (*p && p[-1] != ':') /* find end of middle flags */ 973 { 974 if (*p == COM_BLANK) 975 require_blank = TRUE; 976 ++p; 977 } 978 (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ","); 979 980 while (*p && p[-1] != ':') /* find end of end flags */ 981 { 982 /* Check whether we allow automatic ending of comments */ 983 if (*p == COM_AUTO_END) 984 end_comment_pending = -1; /* means we want to set it */ 985 ++p; 986 } 987 n = copy_option_part(&p, lead_end, COM_MAX_LEN, ","); 988 989 if (end_comment_pending == -1) /* we can set it now */ 990 end_comment_pending = lead_end[n - 1]; 991 992 /* 993 * If the end of the comment is in the same line, don't use 994 * the comment leader. 995 */ 996 if (dir == FORWARD) 997 { 998 for (p = saved_line + lead_len; *p; ++p) 999 if (STRNCMP(p, lead_end, n) == 0) 1000 { 1001 comment_end = p; 1002 lead_len = 0; 1003 break; 1004 } 1005 } 1006 1007 /* 1008 * Doing "o" on a start of comment inserts the middle leader. 1009 */ 1010 if (lead_len > 0) 1011 { 1012 if (current_flag == COM_START) 1013 { 1014 lead_repl = lead_middle; 1015 lead_repl_len = (int)STRLEN(lead_middle); 1016 } 1017 1018 /* 1019 * If we have hit RETURN immediately after the start 1020 * comment leader, then put a space after the middle 1021 * comment leader on the next line. 1022 */ 1023 if (!VIM_ISWHITE(saved_line[lead_len - 1]) 1024 && ((p_extra != NULL 1025 && (int)curwin->w_cursor.col == lead_len) 1026 || (p_extra == NULL 1027 && saved_line[lead_len] == NUL) 1028 || require_blank)) 1029 extra_space = TRUE; 1030 } 1031 break; 1032 } 1033 if (*p == COM_END) 1034 { 1035 /* 1036 * Doing "o" on the end of a comment does not insert leader. 1037 * Remember where the end is, might want to use it to find the 1038 * start (for C-comments). 1039 */ 1040 if (dir == FORWARD) 1041 { 1042 comment_end = skipwhite(saved_line); 1043 lead_len = 0; 1044 break; 1045 } 1046 1047 /* 1048 * Doing "O" on the end of a comment inserts the middle leader. 1049 * Find the string for the middle leader, searching backwards. 1050 */ 1051 while (p > curbuf->b_p_com && *p != ',') 1052 --p; 1053 for (lead_repl = p; lead_repl > curbuf->b_p_com 1054 && lead_repl[-1] != ':'; --lead_repl) 1055 ; 1056 lead_repl_len = (int)(p - lead_repl); 1057 1058 /* We can probably always add an extra space when doing "O" on 1059 * the comment-end */ 1060 extra_space = TRUE; 1061 1062 /* Check whether we allow automatic ending of comments */ 1063 for (p2 = p; *p2 && *p2 != ':'; p2++) 1064 { 1065 if (*p2 == COM_AUTO_END) 1066 end_comment_pending = -1; /* means we want to set it */ 1067 } 1068 if (end_comment_pending == -1) 1069 { 1070 /* Find last character in end-comment string */ 1071 while (*p2 && *p2 != ',') 1072 p2++; 1073 end_comment_pending = p2[-1]; 1074 } 1075 break; 1076 } 1077 if (*p == COM_FIRST) 1078 { 1079 /* 1080 * Comment leader for first line only: Don't repeat leader 1081 * when using "O", blank out leader when using "o". 1082 */ 1083 if (dir == BACKWARD) 1084 lead_len = 0; 1085 else 1086 { 1087 lead_repl = (char_u *)""; 1088 lead_repl_len = 0; 1089 } 1090 break; 1091 } 1092 } 1093 if (lead_len) 1094 { 1095 /* allocate buffer (may concatenate p_extra later) */ 1096 leader = alloc(lead_len + lead_repl_len + extra_space + extra_len 1097 + (second_line_indent > 0 ? second_line_indent : 0) + 1); 1098 allocated = leader; /* remember to free it later */ 1099 1100 if (leader == NULL) 1101 lead_len = 0; 1102 else 1103 { 1104 vim_strncpy(leader, saved_line, lead_len); 1105 1106 /* 1107 * Replace leader with lead_repl, right or left adjusted 1108 */ 1109 if (lead_repl != NULL) 1110 { 1111 int c = 0; 1112 int off = 0; 1113 1114 for (p = lead_flags; *p != NUL && *p != ':'; ) 1115 { 1116 if (*p == COM_RIGHT || *p == COM_LEFT) 1117 c = *p++; 1118 else if (VIM_ISDIGIT(*p) || *p == '-') 1119 off = getdigits(&p); 1120 else 1121 ++p; 1122 } 1123 if (c == COM_RIGHT) /* right adjusted leader */ 1124 { 1125 /* find last non-white in the leader to line up with */ 1126 for (p = leader + lead_len - 1; p > leader 1127 && VIM_ISWHITE(*p); --p) 1128 ; 1129 ++p; 1130 1131 #ifdef FEAT_MBYTE 1132 /* Compute the length of the replaced characters in 1133 * screen characters, not bytes. */ 1134 { 1135 int repl_size = vim_strnsize(lead_repl, 1136 lead_repl_len); 1137 int old_size = 0; 1138 char_u *endp = p; 1139 int l; 1140 1141 while (old_size < repl_size && p > leader) 1142 { 1143 MB_PTR_BACK(leader, p); 1144 old_size += ptr2cells(p); 1145 } 1146 l = lead_repl_len - (int)(endp - p); 1147 if (l != 0) 1148 mch_memmove(endp + l, endp, 1149 (size_t)((leader + lead_len) - endp)); 1150 lead_len += l; 1151 } 1152 #else 1153 if (p < leader + lead_repl_len) 1154 p = leader; 1155 else 1156 p -= lead_repl_len; 1157 #endif 1158 mch_memmove(p, lead_repl, (size_t)lead_repl_len); 1159 if (p + lead_repl_len > leader + lead_len) 1160 p[lead_repl_len] = NUL; 1161 1162 /* blank-out any other chars from the old leader. */ 1163 while (--p >= leader) 1164 { 1165 #ifdef FEAT_MBYTE 1166 int l = mb_head_off(leader, p); 1167 1168 if (l > 1) 1169 { 1170 p -= l; 1171 if (ptr2cells(p) > 1) 1172 { 1173 p[1] = ' '; 1174 --l; 1175 } 1176 mch_memmove(p + 1, p + l + 1, 1177 (size_t)((leader + lead_len) - (p + l + 1))); 1178 lead_len -= l; 1179 *p = ' '; 1180 } 1181 else 1182 #endif 1183 if (!VIM_ISWHITE(*p)) 1184 *p = ' '; 1185 } 1186 } 1187 else /* left adjusted leader */ 1188 { 1189 p = skipwhite(leader); 1190 #ifdef FEAT_MBYTE 1191 /* Compute the length of the replaced characters in 1192 * screen characters, not bytes. Move the part that is 1193 * not to be overwritten. */ 1194 { 1195 int repl_size = vim_strnsize(lead_repl, 1196 lead_repl_len); 1197 int i; 1198 int l; 1199 1200 for (i = 0; i < lead_len && p[i] != NUL; i += l) 1201 { 1202 l = (*mb_ptr2len)(p + i); 1203 if (vim_strnsize(p, i + l) > repl_size) 1204 break; 1205 } 1206 if (i != lead_repl_len) 1207 { 1208 mch_memmove(p + lead_repl_len, p + i, 1209 (size_t)(lead_len - i - (p - leader))); 1210 lead_len += lead_repl_len - i; 1211 } 1212 } 1213 #endif 1214 mch_memmove(p, lead_repl, (size_t)lead_repl_len); 1215 1216 /* Replace any remaining non-white chars in the old 1217 * leader by spaces. Keep Tabs, the indent must 1218 * remain the same. */ 1219 for (p += lead_repl_len; p < leader + lead_len; ++p) 1220 if (!VIM_ISWHITE(*p)) 1221 { 1222 /* Don't put a space before a TAB. */ 1223 if (p + 1 < leader + lead_len && p[1] == TAB) 1224 { 1225 --lead_len; 1226 mch_memmove(p, p + 1, 1227 (leader + lead_len) - p); 1228 } 1229 else 1230 { 1231 #ifdef FEAT_MBYTE 1232 int l = (*mb_ptr2len)(p); 1233 1234 if (l > 1) 1235 { 1236 if (ptr2cells(p) > 1) 1237 { 1238 /* Replace a double-wide char with 1239 * two spaces */ 1240 --l; 1241 *p++ = ' '; 1242 } 1243 mch_memmove(p + 1, p + l, 1244 (leader + lead_len) - p); 1245 lead_len -= l - 1; 1246 } 1247 #endif 1248 *p = ' '; 1249 } 1250 } 1251 *p = NUL; 1252 } 1253 1254 /* Recompute the indent, it may have changed. */ 1255 if (curbuf->b_p_ai 1256 #ifdef FEAT_SMARTINDENT 1257 || do_si 1258 #endif 1259 ) 1260 newindent = get_indent_str(leader, (int)curbuf->b_p_ts, FALSE); 1261 1262 /* Add the indent offset */ 1263 if (newindent + off < 0) 1264 { 1265 off = -newindent; 1266 newindent = 0; 1267 } 1268 else 1269 newindent += off; 1270 1271 /* Correct trailing spaces for the shift, so that 1272 * alignment remains equal. */ 1273 while (off > 0 && lead_len > 0 1274 && leader[lead_len - 1] == ' ') 1275 { 1276 /* Don't do it when there is a tab before the space */ 1277 if (vim_strchr(skipwhite(leader), '\t') != NULL) 1278 break; 1279 --lead_len; 1280 --off; 1281 } 1282 1283 /* If the leader ends in white space, don't add an 1284 * extra space */ 1285 if (lead_len > 0 && VIM_ISWHITE(leader[lead_len - 1])) 1286 extra_space = FALSE; 1287 leader[lead_len] = NUL; 1288 } 1289 1290 if (extra_space) 1291 { 1292 leader[lead_len++] = ' '; 1293 leader[lead_len] = NUL; 1294 } 1295 1296 newcol = lead_len; 1297 1298 /* 1299 * if a new indent will be set below, remove the indent that 1300 * is in the comment leader 1301 */ 1302 if (newindent 1303 #ifdef FEAT_SMARTINDENT 1304 || did_si 1305 #endif 1306 ) 1307 { 1308 while (lead_len && VIM_ISWHITE(*leader)) 1309 { 1310 --lead_len; 1311 --newcol; 1312 ++leader; 1313 } 1314 } 1315 1316 } 1317 #ifdef FEAT_SMARTINDENT 1318 did_si = can_si = FALSE; 1319 #endif 1320 } 1321 else if (comment_end != NULL) 1322 { 1323 /* 1324 * We have finished a comment, so we don't use the leader. 1325 * If this was a C-comment and 'ai' or 'si' is set do a normal 1326 * indent to align with the line containing the start of the 1327 * comment. 1328 */ 1329 if (comment_end[0] == '*' && comment_end[1] == '/' && 1330 (curbuf->b_p_ai 1331 #ifdef FEAT_SMARTINDENT 1332 || do_si 1333 #endif 1334 )) 1335 { 1336 old_cursor = curwin->w_cursor; 1337 curwin->w_cursor.col = (colnr_T)(comment_end - saved_line); 1338 if ((pos = findmatch(NULL, NUL)) != NULL) 1339 { 1340 curwin->w_cursor.lnum = pos->lnum; 1341 newindent = get_indent(); 1342 } 1343 curwin->w_cursor = old_cursor; 1344 } 1345 } 1346 } 1347 #endif 1348 1349 /* (State == INSERT || State == REPLACE), only when dir == FORWARD */ 1350 if (p_extra != NULL) 1351 { 1352 *p_extra = saved_char; /* restore char that NUL replaced */ 1353 1354 /* 1355 * When 'ai' set or "flags" has OPENLINE_DELSPACES, skip to the first 1356 * non-blank. 1357 * 1358 * When in REPLACE mode, put the deleted blanks on the replace stack, 1359 * preceded by a NUL, so they can be put back when a BS is entered. 1360 */ 1361 if (REPLACE_NORMAL(State)) 1362 replace_push(NUL); /* end of extra blanks */ 1363 if (curbuf->b_p_ai || (flags & OPENLINE_DELSPACES)) 1364 { 1365 while ((*p_extra == ' ' || *p_extra == '\t') 1366 #ifdef FEAT_MBYTE 1367 && (!enc_utf8 1368 || !utf_iscomposing(utf_ptr2char(p_extra + 1))) 1369 #endif 1370 ) 1371 { 1372 if (REPLACE_NORMAL(State)) 1373 replace_push(*p_extra); 1374 ++p_extra; 1375 ++less_cols_off; 1376 } 1377 } 1378 if (*p_extra != NUL) 1379 did_ai = FALSE; /* append some text, don't truncate now */ 1380 1381 /* columns for marks adjusted for removed columns */ 1382 less_cols = (int)(p_extra - saved_line); 1383 } 1384 1385 if (p_extra == NULL) 1386 p_extra = (char_u *)""; /* append empty line */ 1387 1388 #ifdef FEAT_COMMENTS 1389 /* concatenate leader and p_extra, if there is a leader */ 1390 if (lead_len) 1391 { 1392 if (flags & OPENLINE_COM_LIST && second_line_indent > 0) 1393 { 1394 int i; 1395 int padding = second_line_indent 1396 - (newindent + (int)STRLEN(leader)); 1397 1398 /* Here whitespace is inserted after the comment char. 1399 * Below, set_indent(newindent, SIN_INSERT) will insert the 1400 * whitespace needed before the comment char. */ 1401 for (i = 0; i < padding; i++) 1402 { 1403 STRCAT(leader, " "); 1404 less_cols--; 1405 newcol++; 1406 } 1407 } 1408 STRCAT(leader, p_extra); 1409 p_extra = leader; 1410 did_ai = TRUE; /* So truncating blanks works with comments */ 1411 less_cols -= lead_len; 1412 } 1413 else 1414 end_comment_pending = NUL; /* turns out there was no leader */ 1415 #endif 1416 1417 old_cursor = curwin->w_cursor; 1418 if (dir == BACKWARD) 1419 --curwin->w_cursor.lnum; 1420 #ifdef FEAT_VREPLACE 1421 if (!(State & VREPLACE_FLAG) || old_cursor.lnum >= orig_line_count) 1422 #endif 1423 { 1424 if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_T)0, FALSE) 1425 == FAIL) 1426 goto theend; 1427 /* Postpone calling changed_lines(), because it would mess up folding 1428 * with markers. 1429 * Skip mark_adjust when adding a line after the last one, there can't 1430 * be marks there. But still needed in diff mode. */ 1431 if (curwin->w_cursor.lnum + 1 < curbuf->b_ml.ml_line_count 1432 #ifdef FEAT_DIFF 1433 || curwin->w_p_diff 1434 #endif 1435 ) 1436 mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L); 1437 did_append = TRUE; 1438 } 1439 #ifdef FEAT_VREPLACE 1440 else 1441 { 1442 /* 1443 * In VREPLACE mode we are starting to replace the next line. 1444 */ 1445 curwin->w_cursor.lnum++; 1446 if (curwin->w_cursor.lnum >= Insstart.lnum + vr_lines_changed) 1447 { 1448 /* In case we NL to a new line, BS to the previous one, and NL 1449 * again, we don't want to save the new line for undo twice. 1450 */ 1451 (void)u_save_cursor(); /* errors are ignored! */ 1452 vr_lines_changed++; 1453 } 1454 ml_replace(curwin->w_cursor.lnum, p_extra, TRUE); 1455 changed_bytes(curwin->w_cursor.lnum, 0); 1456 curwin->w_cursor.lnum--; 1457 did_append = FALSE; 1458 } 1459 #endif 1460 1461 if (newindent 1462 #ifdef FEAT_SMARTINDENT 1463 || did_si 1464 #endif 1465 ) 1466 { 1467 ++curwin->w_cursor.lnum; 1468 #ifdef FEAT_SMARTINDENT 1469 if (did_si) 1470 { 1471 int sw = (int)get_sw_value(curbuf); 1472 1473 if (p_sr) 1474 newindent -= newindent % sw; 1475 newindent += sw; 1476 } 1477 #endif 1478 /* Copy the indent */ 1479 if (curbuf->b_p_ci) 1480 { 1481 (void)copy_indent(newindent, saved_line); 1482 1483 /* 1484 * Set the 'preserveindent' option so that any further screwing 1485 * with the line doesn't entirely destroy our efforts to preserve 1486 * it. It gets restored at the function end. 1487 */ 1488 curbuf->b_p_pi = TRUE; 1489 } 1490 else 1491 (void)set_indent(newindent, SIN_INSERT); 1492 less_cols -= curwin->w_cursor.col; 1493 1494 ai_col = curwin->w_cursor.col; 1495 1496 /* 1497 * In REPLACE mode, for each character in the new indent, there must 1498 * be a NUL on the replace stack, for when it is deleted with BS 1499 */ 1500 if (REPLACE_NORMAL(State)) 1501 for (n = 0; n < (int)curwin->w_cursor.col; ++n) 1502 replace_push(NUL); 1503 newcol += curwin->w_cursor.col; 1504 #ifdef FEAT_SMARTINDENT 1505 if (no_si) 1506 did_si = FALSE; 1507 #endif 1508 } 1509 1510 #ifdef FEAT_COMMENTS 1511 /* 1512 * In REPLACE mode, for each character in the extra leader, there must be 1513 * a NUL on the replace stack, for when it is deleted with BS. 1514 */ 1515 if (REPLACE_NORMAL(State)) 1516 while (lead_len-- > 0) 1517 replace_push(NUL); 1518 #endif 1519 1520 curwin->w_cursor = old_cursor; 1521 1522 if (dir == FORWARD) 1523 { 1524 if (trunc_line || (State & INSERT)) 1525 { 1526 /* truncate current line at cursor */ 1527 saved_line[curwin->w_cursor.col] = NUL; 1528 /* Remove trailing white space, unless OPENLINE_KEEPTRAIL used. */ 1529 if (trunc_line && !(flags & OPENLINE_KEEPTRAIL)) 1530 truncate_spaces(saved_line); 1531 ml_replace(curwin->w_cursor.lnum, saved_line, FALSE); 1532 saved_line = NULL; 1533 if (did_append) 1534 { 1535 changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col, 1536 curwin->w_cursor.lnum + 1, 1L); 1537 did_append = FALSE; 1538 1539 /* Move marks after the line break to the new line. */ 1540 if (flags & OPENLINE_MARKFIX) 1541 mark_col_adjust(curwin->w_cursor.lnum, 1542 curwin->w_cursor.col + less_cols_off, 1543 1L, (long)-less_cols); 1544 } 1545 else 1546 changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); 1547 } 1548 1549 /* 1550 * Put the cursor on the new line. Careful: the scrollup() above may 1551 * have moved w_cursor, we must use old_cursor. 1552 */ 1553 curwin->w_cursor.lnum = old_cursor.lnum + 1; 1554 } 1555 if (did_append) 1556 changed_lines(curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L); 1557 1558 curwin->w_cursor.col = newcol; 1559 #ifdef FEAT_VIRTUALEDIT 1560 curwin->w_cursor.coladd = 0; 1561 #endif 1562 1563 #if defined(FEAT_VREPLACE) && (defined(FEAT_LISP) || defined(FEAT_CINDENT)) 1564 /* 1565 * In VREPLACE mode, we are handling the replace stack ourselves, so stop 1566 * fixthisline() from doing it (via change_indent()) by telling it we're in 1567 * normal INSERT mode. 1568 */ 1569 if (State & VREPLACE_FLAG) 1570 { 1571 vreplace_mode = State; /* So we know to put things right later */ 1572 State = INSERT; 1573 } 1574 else 1575 vreplace_mode = 0; 1576 #endif 1577 #ifdef FEAT_LISP 1578 /* 1579 * May do lisp indenting. 1580 */ 1581 if (!p_paste 1582 # ifdef FEAT_COMMENTS 1583 && leader == NULL 1584 # endif 1585 && curbuf->b_p_lisp 1586 && curbuf->b_p_ai) 1587 { 1588 fixthisline(get_lisp_indent); 1589 p = ml_get_curline(); 1590 ai_col = (colnr_T)(skipwhite(p) - p); 1591 } 1592 #endif 1593 #ifdef FEAT_CINDENT 1594 /* 1595 * May do indenting after opening a new line. 1596 */ 1597 if (!p_paste 1598 && (curbuf->b_p_cin 1599 # ifdef FEAT_EVAL 1600 || *curbuf->b_p_inde != NUL 1601 # endif 1602 ) 1603 && in_cinkeys(dir == FORWARD 1604 ? KEY_OPEN_FORW 1605 : KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum))) 1606 { 1607 do_c_expr_indent(); 1608 p = ml_get_curline(); 1609 ai_col = (colnr_T)(skipwhite(p) - p); 1610 } 1611 #endif 1612 #if defined(FEAT_VREPLACE) && (defined(FEAT_LISP) || defined(FEAT_CINDENT)) 1613 if (vreplace_mode != 0) 1614 State = vreplace_mode; 1615 #endif 1616 1617 #ifdef FEAT_VREPLACE 1618 /* 1619 * Finally, VREPLACE gets the stuff on the new line, then puts back the 1620 * original line, and inserts the new stuff char by char, pushing old stuff 1621 * onto the replace stack (via ins_char()). 1622 */ 1623 if (State & VREPLACE_FLAG) 1624 { 1625 /* Put new line in p_extra */ 1626 p_extra = vim_strsave(ml_get_curline()); 1627 if (p_extra == NULL) 1628 goto theend; 1629 1630 /* Put back original line */ 1631 ml_replace(curwin->w_cursor.lnum, next_line, FALSE); 1632 1633 /* Insert new stuff into line again */ 1634 curwin->w_cursor.col = 0; 1635 #ifdef FEAT_VIRTUALEDIT 1636 curwin->w_cursor.coladd = 0; 1637 #endif 1638 ins_bytes(p_extra); /* will call changed_bytes() */ 1639 vim_free(p_extra); 1640 next_line = NULL; 1641 } 1642 #endif 1643 1644 retval = TRUE; /* success! */ 1645 theend: 1646 curbuf->b_p_pi = saved_pi; 1647 vim_free(saved_line); 1648 vim_free(next_line); 1649 vim_free(allocated); 1650 return retval; 1651 } 1652 1653 #if defined(FEAT_COMMENTS) || defined(PROTO) 1654 /* 1655 * get_leader_len() returns the length in bytes of the prefix of the given 1656 * string which introduces a comment. If this string is not a comment then 1657 * 0 is returned. 1658 * When "flags" is not NULL, it is set to point to the flags of the recognized 1659 * comment leader. 1660 * "backward" must be true for the "O" command. 1661 * If "include_space" is set, include trailing whitespace while calculating the 1662 * length. 1663 */ 1664 int 1665 get_leader_len( 1666 char_u *line, 1667 char_u **flags, 1668 int backward, 1669 int include_space) 1670 { 1671 int i, j; 1672 int result; 1673 int got_com = FALSE; 1674 int found_one; 1675 char_u part_buf[COM_MAX_LEN]; /* buffer for one option part */ 1676 char_u *string; /* pointer to comment string */ 1677 char_u *list; 1678 int middle_match_len = 0; 1679 char_u *prev_list; 1680 char_u *saved_flags = NULL; 1681 1682 result = i = 0; 1683 while (VIM_ISWHITE(line[i])) /* leading white space is ignored */ 1684 ++i; 1685 1686 /* 1687 * Repeat to match several nested comment strings. 1688 */ 1689 while (line[i] != NUL) 1690 { 1691 /* 1692 * scan through the 'comments' option for a match 1693 */ 1694 found_one = FALSE; 1695 for (list = curbuf->b_p_com; *list; ) 1696 { 1697 /* Get one option part into part_buf[]. Advance "list" to next 1698 * one. Put "string" at start of string. */ 1699 if (!got_com && flags != NULL) 1700 *flags = list; /* remember where flags started */ 1701 prev_list = list; 1702 (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ","); 1703 string = vim_strchr(part_buf, ':'); 1704 if (string == NULL) /* missing ':', ignore this part */ 1705 continue; 1706 *string++ = NUL; /* isolate flags from string */ 1707 1708 /* If we found a middle match previously, use that match when this 1709 * is not a middle or end. */ 1710 if (middle_match_len != 0 1711 && vim_strchr(part_buf, COM_MIDDLE) == NULL 1712 && vim_strchr(part_buf, COM_END) == NULL) 1713 break; 1714 1715 /* When we already found a nested comment, only accept further 1716 * nested comments. */ 1717 if (got_com && vim_strchr(part_buf, COM_NEST) == NULL) 1718 continue; 1719 1720 /* When 'O' flag present and using "O" command skip this one. */ 1721 if (backward && vim_strchr(part_buf, COM_NOBACK) != NULL) 1722 continue; 1723 1724 /* Line contents and string must match. 1725 * When string starts with white space, must have some white space 1726 * (but the amount does not need to match, there might be a mix of 1727 * TABs and spaces). */ 1728 if (VIM_ISWHITE(string[0])) 1729 { 1730 if (i == 0 || !VIM_ISWHITE(line[i - 1])) 1731 continue; /* missing white space */ 1732 while (VIM_ISWHITE(string[0])) 1733 ++string; 1734 } 1735 for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j) 1736 ; 1737 if (string[j] != NUL) 1738 continue; /* string doesn't match */ 1739 1740 /* When 'b' flag used, there must be white space or an 1741 * end-of-line after the string in the line. */ 1742 if (vim_strchr(part_buf, COM_BLANK) != NULL 1743 && !VIM_ISWHITE(line[i + j]) && line[i + j] != NUL) 1744 continue; 1745 1746 /* We have found a match, stop searching unless this is a middle 1747 * comment. The middle comment can be a substring of the end 1748 * comment in which case it's better to return the length of the 1749 * end comment and its flags. Thus we keep searching with middle 1750 * and end matches and use an end match if it matches better. */ 1751 if (vim_strchr(part_buf, COM_MIDDLE) != NULL) 1752 { 1753 if (middle_match_len == 0) 1754 { 1755 middle_match_len = j; 1756 saved_flags = prev_list; 1757 } 1758 continue; 1759 } 1760 if (middle_match_len != 0 && j > middle_match_len) 1761 /* Use this match instead of the middle match, since it's a 1762 * longer thus better match. */ 1763 middle_match_len = 0; 1764 1765 if (middle_match_len == 0) 1766 i += j; 1767 found_one = TRUE; 1768 break; 1769 } 1770 1771 if (middle_match_len != 0) 1772 { 1773 /* Use the previously found middle match after failing to find a 1774 * match with an end. */ 1775 if (!got_com && flags != NULL) 1776 *flags = saved_flags; 1777 i += middle_match_len; 1778 found_one = TRUE; 1779 } 1780 1781 /* No match found, stop scanning. */ 1782 if (!found_one) 1783 break; 1784 1785 result = i; 1786 1787 /* Include any trailing white space. */ 1788 while (VIM_ISWHITE(line[i])) 1789 ++i; 1790 1791 if (include_space) 1792 result = i; 1793 1794 /* If this comment doesn't nest, stop here. */ 1795 got_com = TRUE; 1796 if (vim_strchr(part_buf, COM_NEST) == NULL) 1797 break; 1798 } 1799 return result; 1800 } 1801 1802 /* 1803 * Return the offset at which the last comment in line starts. If there is no 1804 * comment in the whole line, -1 is returned. 1805 * 1806 * When "flags" is not null, it is set to point to the flags describing the 1807 * recognized comment leader. 1808 */ 1809 int 1810 get_last_leader_offset(char_u *line, char_u **flags) 1811 { 1812 int result = -1; 1813 int i, j; 1814 int lower_check_bound = 0; 1815 char_u *string; 1816 char_u *com_leader; 1817 char_u *com_flags; 1818 char_u *list; 1819 int found_one; 1820 char_u part_buf[COM_MAX_LEN]; /* buffer for one option part */ 1821 1822 /* 1823 * Repeat to match several nested comment strings. 1824 */ 1825 i = (int)STRLEN(line); 1826 while (--i >= lower_check_bound) 1827 { 1828 /* 1829 * scan through the 'comments' option for a match 1830 */ 1831 found_one = FALSE; 1832 for (list = curbuf->b_p_com; *list; ) 1833 { 1834 char_u *flags_save = list; 1835 1836 /* 1837 * Get one option part into part_buf[]. Advance list to next one. 1838 * put string at start of string. 1839 */ 1840 (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ","); 1841 string = vim_strchr(part_buf, ':'); 1842 if (string == NULL) /* If everything is fine, this cannot actually 1843 * happen. */ 1844 { 1845 continue; 1846 } 1847 *string++ = NUL; /* Isolate flags from string. */ 1848 com_leader = string; 1849 1850 /* 1851 * Line contents and string must match. 1852 * When string starts with white space, must have some white space 1853 * (but the amount does not need to match, there might be a mix of 1854 * TABs and spaces). 1855 */ 1856 if (VIM_ISWHITE(string[0])) 1857 { 1858 if (i == 0 || !VIM_ISWHITE(line[i - 1])) 1859 continue; 1860 while (VIM_ISWHITE(string[0])) 1861 ++string; 1862 } 1863 for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j) 1864 /* do nothing */; 1865 if (string[j] != NUL) 1866 continue; 1867 1868 /* 1869 * When 'b' flag used, there must be white space or an 1870 * end-of-line after the string in the line. 1871 */ 1872 if (vim_strchr(part_buf, COM_BLANK) != NULL 1873 && !VIM_ISWHITE(line[i + j]) && line[i + j] != NUL) 1874 { 1875 continue; 1876 } 1877 1878 /* 1879 * We have found a match, stop searching. 1880 */ 1881 found_one = TRUE; 1882 1883 if (flags) 1884 *flags = flags_save; 1885 com_flags = flags_save; 1886 1887 break; 1888 } 1889 1890 if (found_one) 1891 { 1892 char_u part_buf2[COM_MAX_LEN]; /* buffer for one option part */ 1893 int len1, len2, off; 1894 1895 result = i; 1896 /* 1897 * If this comment nests, continue searching. 1898 */ 1899 if (vim_strchr(part_buf, COM_NEST) != NULL) 1900 continue; 1901 1902 lower_check_bound = i; 1903 1904 /* Let's verify whether the comment leader found is a substring 1905 * of other comment leaders. If it is, let's adjust the 1906 * lower_check_bound so that we make sure that we have determined 1907 * the comment leader correctly. 1908 */ 1909 1910 while (VIM_ISWHITE(*com_leader)) 1911 ++com_leader; 1912 len1 = (int)STRLEN(com_leader); 1913 1914 for (list = curbuf->b_p_com; *list; ) 1915 { 1916 char_u *flags_save = list; 1917 1918 (void)copy_option_part(&list, part_buf2, COM_MAX_LEN, ","); 1919 if (flags_save == com_flags) 1920 continue; 1921 string = vim_strchr(part_buf2, ':'); 1922 ++string; 1923 while (VIM_ISWHITE(*string)) 1924 ++string; 1925 len2 = (int)STRLEN(string); 1926 if (len2 == 0) 1927 continue; 1928 1929 /* Now we have to verify whether string ends with a substring 1930 * beginning the com_leader. */ 1931 for (off = (len2 > i ? i : len2); off > 0 && off + len1 > len2;) 1932 { 1933 --off; 1934 if (!STRNCMP(string + off, com_leader, len2 - off)) 1935 { 1936 if (i - off < lower_check_bound) 1937 lower_check_bound = i - off; 1938 } 1939 } 1940 } 1941 } 1942 } 1943 return result; 1944 } 1945 #endif 1946 1947 /* 1948 * Return the number of window lines occupied by buffer line "lnum". 1949 */ 1950 int 1951 plines(linenr_T lnum) 1952 { 1953 return plines_win(curwin, lnum, TRUE); 1954 } 1955 1956 int 1957 plines_win( 1958 win_T *wp, 1959 linenr_T lnum, 1960 int winheight) /* when TRUE limit to window height */ 1961 { 1962 #if defined(FEAT_DIFF) || defined(PROTO) 1963 /* Check for filler lines above this buffer line. When folded the result 1964 * is one line anyway. */ 1965 return plines_win_nofill(wp, lnum, winheight) + diff_check_fill(wp, lnum); 1966 } 1967 1968 int 1969 plines_nofill(linenr_T lnum) 1970 { 1971 return plines_win_nofill(curwin, lnum, TRUE); 1972 } 1973 1974 int 1975 plines_win_nofill( 1976 win_T *wp, 1977 linenr_T lnum, 1978 int winheight) /* when TRUE limit to window height */ 1979 { 1980 #endif 1981 int lines; 1982 1983 if (!wp->w_p_wrap) 1984 return 1; 1985 1986 #ifdef FEAT_WINDOWS 1987 if (wp->w_width == 0) 1988 return 1; 1989 #endif 1990 1991 #ifdef FEAT_FOLDING 1992 /* A folded lines is handled just like an empty line. */ 1993 /* NOTE: Caller must handle lines that are MAYBE folded. */ 1994 if (lineFolded(wp, lnum) == TRUE) 1995 return 1; 1996 #endif 1997 1998 lines = plines_win_nofold(wp, lnum); 1999 if (winheight > 0 && lines > wp->w_height) 2000 return (int)wp->w_height; 2001 return lines; 2002 } 2003 2004 /* 2005 * Return number of window lines physical line "lnum" will occupy in window 2006 * "wp". Does not care about folding, 'wrap' or 'diff'. 2007 */ 2008 int 2009 plines_win_nofold(win_T *wp, linenr_T lnum) 2010 { 2011 char_u *s; 2012 long col; 2013 int width; 2014 2015 s = ml_get_buf(wp->w_buffer, lnum, FALSE); 2016 if (*s == NUL) /* empty line */ 2017 return 1; 2018 col = win_linetabsize(wp, s, (colnr_T)MAXCOL); 2019 2020 /* 2021 * If list mode is on, then the '$' at the end of the line may take up one 2022 * extra column. 2023 */ 2024 if (wp->w_p_list && lcs_eol != NUL) 2025 col += 1; 2026 2027 /* 2028 * Add column offset for 'number', 'relativenumber' and 'foldcolumn'. 2029 */ 2030 width = W_WIDTH(wp) - win_col_off(wp); 2031 if (width <= 0) 2032 return 32000; 2033 if (col <= width) 2034 return 1; 2035 col -= width; 2036 width += win_col_off2(wp); 2037 return (col + (width - 1)) / width + 1; 2038 } 2039 2040 /* 2041 * Like plines_win(), but only reports the number of physical screen lines 2042 * used from the start of the line to the given column number. 2043 */ 2044 int 2045 plines_win_col(win_T *wp, linenr_T lnum, long column) 2046 { 2047 long col; 2048 char_u *s; 2049 int lines = 0; 2050 int width; 2051 char_u *line; 2052 2053 #ifdef FEAT_DIFF 2054 /* Check for filler lines above this buffer line. When folded the result 2055 * is one line anyway. */ 2056 lines = diff_check_fill(wp, lnum); 2057 #endif 2058 2059 if (!wp->w_p_wrap) 2060 return lines + 1; 2061 2062 #ifdef FEAT_WINDOWS 2063 if (wp->w_width == 0) 2064 return lines + 1; 2065 #endif 2066 2067 line = s = ml_get_buf(wp->w_buffer, lnum, FALSE); 2068 2069 col = 0; 2070 while (*s != NUL && --column >= 0) 2071 { 2072 col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL); 2073 MB_PTR_ADV(s); 2074 } 2075 2076 /* 2077 * If *s is a TAB, and the TAB is not displayed as ^I, and we're not in 2078 * INSERT mode, then col must be adjusted so that it represents the last 2079 * screen position of the TAB. This only fixes an error when the TAB wraps 2080 * from one screen line to the next (when 'columns' is not a multiple of 2081 * 'ts') -- webb. 2082 */ 2083 if (*s == TAB && (State & NORMAL) && (!wp->w_p_list || lcs_tab1)) 2084 col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL) - 1; 2085 2086 /* 2087 * Add column offset for 'number', 'relativenumber', 'foldcolumn', etc. 2088 */ 2089 width = W_WIDTH(wp) - win_col_off(wp); 2090 if (width <= 0) 2091 return 9999; 2092 2093 lines += 1; 2094 if (col > width) 2095 lines += (col - width) / (width + win_col_off2(wp)) + 1; 2096 return lines; 2097 } 2098 2099 int 2100 plines_m_win(win_T *wp, linenr_T first, linenr_T last) 2101 { 2102 int count = 0; 2103 2104 while (first <= last) 2105 { 2106 #ifdef FEAT_FOLDING 2107 int x; 2108 2109 /* Check if there are any really folded lines, but also included lines 2110 * that are maybe folded. */ 2111 x = foldedCount(wp, first, NULL); 2112 if (x > 0) 2113 { 2114 ++count; /* count 1 for "+-- folded" line */ 2115 first += x; 2116 } 2117 else 2118 #endif 2119 { 2120 #ifdef FEAT_DIFF 2121 if (first == wp->w_topline) 2122 count += plines_win_nofill(wp, first, TRUE) + wp->w_topfill; 2123 else 2124 #endif 2125 count += plines_win(wp, first, TRUE); 2126 ++first; 2127 } 2128 } 2129 return (count); 2130 } 2131 2132 #if defined(FEAT_VREPLACE) || defined(FEAT_INS_EXPAND) || defined(PROTO) 2133 /* 2134 * Insert string "p" at the cursor position. Stops at a NUL byte. 2135 * Handles Replace mode and multi-byte characters. 2136 */ 2137 void 2138 ins_bytes(char_u *p) 2139 { 2140 ins_bytes_len(p, (int)STRLEN(p)); 2141 } 2142 #endif 2143 2144 #if defined(FEAT_VREPLACE) || defined(FEAT_INS_EXPAND) \ 2145 || defined(FEAT_COMMENTS) || defined(FEAT_MBYTE) || defined(PROTO) 2146 /* 2147 * Insert string "p" with length "len" at the cursor position. 2148 * Handles Replace mode and multi-byte characters. 2149 */ 2150 void 2151 ins_bytes_len(char_u *p, int len) 2152 { 2153 int i; 2154 # ifdef FEAT_MBYTE 2155 int n; 2156 2157 if (has_mbyte) 2158 for (i = 0; i < len; i += n) 2159 { 2160 if (enc_utf8) 2161 /* avoid reading past p[len] */ 2162 n = utfc_ptr2len_len(p + i, len - i); 2163 else 2164 n = (*mb_ptr2len)(p + i); 2165 ins_char_bytes(p + i, n); 2166 } 2167 else 2168 # endif 2169 for (i = 0; i < len; ++i) 2170 ins_char(p[i]); 2171 } 2172 #endif 2173 2174 /* 2175 * Insert or replace a single character at the cursor position. 2176 * When in REPLACE or VREPLACE mode, replace any existing character. 2177 * Caller must have prepared for undo. 2178 * For multi-byte characters we get the whole character, the caller must 2179 * convert bytes to a character. 2180 */ 2181 void 2182 ins_char(int c) 2183 { 2184 char_u buf[MB_MAXBYTES + 1]; 2185 int n = 1; 2186 2187 #ifdef FEAT_MBYTE 2188 n = (*mb_char2bytes)(c, buf); 2189 2190 /* When "c" is 0x100, 0x200, etc. we don't want to insert a NUL byte. 2191 * Happens for CTRL-Vu9900. */ 2192 if (buf[0] == 0) 2193 buf[0] = '\n'; 2194 #else 2195 buf[0] = c; 2196 #endif 2197 2198 ins_char_bytes(buf, n); 2199 } 2200 2201 void 2202 ins_char_bytes(char_u *buf, int charlen) 2203 { 2204 int c = buf[0]; 2205 int newlen; /* nr of bytes inserted */ 2206 int oldlen; /* nr of bytes deleted (0 when not replacing) */ 2207 char_u *p; 2208 char_u *newp; 2209 char_u *oldp; 2210 int linelen; /* length of old line including NUL */ 2211 colnr_T col; 2212 linenr_T lnum = curwin->w_cursor.lnum; 2213 int i; 2214 2215 #ifdef FEAT_VIRTUALEDIT 2216 /* Break tabs if needed. */ 2217 if (virtual_active() && curwin->w_cursor.coladd > 0) 2218 coladvance_force(getviscol()); 2219 #endif 2220 2221 col = curwin->w_cursor.col; 2222 oldp = ml_get(lnum); 2223 linelen = (int)STRLEN(oldp) + 1; 2224 2225 /* The lengths default to the values for when not replacing. */ 2226 oldlen = 0; 2227 newlen = charlen; 2228 2229 if (State & REPLACE_FLAG) 2230 { 2231 #ifdef FEAT_VREPLACE 2232 if (State & VREPLACE_FLAG) 2233 { 2234 colnr_T new_vcol = 0; /* init for GCC */ 2235 colnr_T vcol; 2236 int old_list; 2237 #ifndef FEAT_MBYTE 2238 char_u buf[2]; 2239 #endif 2240 2241 /* 2242 * Disable 'list' temporarily, unless 'cpo' contains the 'L' flag. 2243 * Returns the old value of list, so when finished, 2244 * curwin->w_p_list should be set back to this. 2245 */ 2246 old_list = curwin->w_p_list; 2247 if (old_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) 2248 curwin->w_p_list = FALSE; 2249 2250 /* 2251 * In virtual replace mode each character may replace one or more 2252 * characters (zero if it's a TAB). Count the number of bytes to 2253 * be deleted to make room for the new character, counting screen 2254 * cells. May result in adding spaces to fill a gap. 2255 */ 2256 getvcol(curwin, &curwin->w_cursor, NULL, &vcol, NULL); 2257 #ifndef FEAT_MBYTE 2258 buf[0] = c; 2259 buf[1] = NUL; 2260 #endif 2261 new_vcol = vcol + chartabsize(buf, vcol); 2262 while (oldp[col + oldlen] != NUL && vcol < new_vcol) 2263 { 2264 vcol += chartabsize(oldp + col + oldlen, vcol); 2265 /* Don't need to remove a TAB that takes us to the right 2266 * position. */ 2267 if (vcol > new_vcol && oldp[col + oldlen] == TAB) 2268 break; 2269 #ifdef FEAT_MBYTE 2270 oldlen += (*mb_ptr2len)(oldp + col + oldlen); 2271 #else 2272 ++oldlen; 2273 #endif 2274 /* Deleted a bit too much, insert spaces. */ 2275 if (vcol > new_vcol) 2276 newlen += vcol - new_vcol; 2277 } 2278 curwin->w_p_list = old_list; 2279 } 2280 else 2281 #endif 2282 if (oldp[col] != NUL) 2283 { 2284 /* normal replace */ 2285 #ifdef FEAT_MBYTE 2286 oldlen = (*mb_ptr2len)(oldp + col); 2287 #else 2288 oldlen = 1; 2289 #endif 2290 } 2291 2292 2293 /* Push the replaced bytes onto the replace stack, so that they can be 2294 * put back when BS is used. The bytes of a multi-byte character are 2295 * done the other way around, so that the first byte is popped off 2296 * first (it tells the byte length of the character). */ 2297 replace_push(NUL); 2298 for (i = 0; i < oldlen; ++i) 2299 { 2300 #ifdef FEAT_MBYTE 2301 if (has_mbyte) 2302 i += replace_push_mb(oldp + col + i) - 1; 2303 else 2304 #endif 2305 replace_push(oldp[col + i]); 2306 } 2307 } 2308 2309 newp = alloc_check((unsigned)(linelen + newlen - oldlen)); 2310 if (newp == NULL) 2311 return; 2312 2313 /* Copy bytes before the cursor. */ 2314 if (col > 0) 2315 mch_memmove(newp, oldp, (size_t)col); 2316 2317 /* Copy bytes after the changed character(s). */ 2318 p = newp + col; 2319 mch_memmove(p + newlen, oldp + col + oldlen, 2320 (size_t)(linelen - col - oldlen)); 2321 2322 /* Insert or overwrite the new character. */ 2323 #ifdef FEAT_MBYTE 2324 mch_memmove(p, buf, charlen); 2325 i = charlen; 2326 #else 2327 *p = c; 2328 i = 1; 2329 #endif 2330 2331 /* Fill with spaces when necessary. */ 2332 while (i < newlen) 2333 p[i++] = ' '; 2334 2335 /* Replace the line in the buffer. */ 2336 ml_replace(lnum, newp, FALSE); 2337 2338 /* mark the buffer as changed and prepare for displaying */ 2339 changed_bytes(lnum, col); 2340 2341 /* 2342 * If we're in Insert or Replace mode and 'showmatch' is set, then briefly 2343 * show the match for right parens and braces. 2344 */ 2345 if (p_sm && (State & INSERT) 2346 && msg_silent == 0 2347 #ifdef FEAT_INS_EXPAND 2348 && !ins_compl_active() 2349 #endif 2350 ) 2351 { 2352 #ifdef FEAT_MBYTE 2353 if (has_mbyte) 2354 showmatch(mb_ptr2char(buf)); 2355 else 2356 #endif 2357 showmatch(c); 2358 } 2359 2360 #ifdef FEAT_RIGHTLEFT 2361 if (!p_ri || (State & REPLACE_FLAG)) 2362 #endif 2363 { 2364 /* Normal insert: move cursor right */ 2365 #ifdef FEAT_MBYTE 2366 curwin->w_cursor.col += charlen; 2367 #else 2368 ++curwin->w_cursor.col; 2369 #endif 2370 } 2371 /* 2372 * TODO: should try to update w_row here, to avoid recomputing it later. 2373 */ 2374 } 2375 2376 /* 2377 * Insert a string at the cursor position. 2378 * Note: Does NOT handle Replace mode. 2379 * Caller must have prepared for undo. 2380 */ 2381 void 2382 ins_str(char_u *s) 2383 { 2384 char_u *oldp, *newp; 2385 int newlen = (int)STRLEN(s); 2386 int oldlen; 2387 colnr_T col; 2388 linenr_T lnum = curwin->w_cursor.lnum; 2389 2390 #ifdef FEAT_VIRTUALEDIT 2391 if (virtual_active() && curwin->w_cursor.coladd > 0) 2392 coladvance_force(getviscol()); 2393 #endif 2394 2395 col = curwin->w_cursor.col; 2396 oldp = ml_get(lnum); 2397 oldlen = (int)STRLEN(oldp); 2398 2399 newp = alloc_check((unsigned)(oldlen + newlen + 1)); 2400 if (newp == NULL) 2401 return; 2402 if (col > 0) 2403 mch_memmove(newp, oldp, (size_t)col); 2404 mch_memmove(newp + col, s, (size_t)newlen); 2405 mch_memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1)); 2406 ml_replace(lnum, newp, FALSE); 2407 changed_bytes(lnum, col); 2408 curwin->w_cursor.col += newlen; 2409 } 2410 2411 /* 2412 * Delete one character under the cursor. 2413 * If "fixpos" is TRUE, don't leave the cursor on the NUL after the line. 2414 * Caller must have prepared for undo. 2415 * 2416 * return FAIL for failure, OK otherwise 2417 */ 2418 int 2419 del_char(int fixpos) 2420 { 2421 #ifdef FEAT_MBYTE 2422 if (has_mbyte) 2423 { 2424 /* Make sure the cursor is at the start of a character. */ 2425 mb_adjust_cursor(); 2426 if (*ml_get_cursor() == NUL) 2427 return FAIL; 2428 return del_chars(1L, fixpos); 2429 } 2430 #endif 2431 return del_bytes(1L, fixpos, TRUE); 2432 } 2433 2434 #if defined(FEAT_MBYTE) || defined(PROTO) 2435 /* 2436 * Like del_bytes(), but delete characters instead of bytes. 2437 */ 2438 int 2439 del_chars(long count, int fixpos) 2440 { 2441 long bytes = 0; 2442 long i; 2443 char_u *p; 2444 int l; 2445 2446 p = ml_get_cursor(); 2447 for (i = 0; i < count && *p != NUL; ++i) 2448 { 2449 l = (*mb_ptr2len)(p); 2450 bytes += l; 2451 p += l; 2452 } 2453 return del_bytes(bytes, fixpos, TRUE); 2454 } 2455 #endif 2456 2457 /* 2458 * Delete "count" bytes under the cursor. 2459 * If "fixpos" is TRUE, don't leave the cursor on the NUL after the line. 2460 * Caller must have prepared for undo. 2461 * 2462 * return FAIL for failure, OK otherwise 2463 */ 2464 int 2465 del_bytes( 2466 long count, 2467 int fixpos_arg, 2468 int use_delcombine UNUSED) /* 'delcombine' option applies */ 2469 { 2470 char_u *oldp, *newp; 2471 colnr_T oldlen; 2472 linenr_T lnum = curwin->w_cursor.lnum; 2473 colnr_T col = curwin->w_cursor.col; 2474 int was_alloced; 2475 long movelen; 2476 int fixpos = fixpos_arg; 2477 2478 oldp = ml_get(lnum); 2479 oldlen = (int)STRLEN(oldp); 2480 2481 /* 2482 * Can't do anything when the cursor is on the NUL after the line. 2483 */ 2484 if (col >= oldlen) 2485 return FAIL; 2486 2487 #ifdef FEAT_MBYTE 2488 /* If 'delcombine' is set and deleting (less than) one character, only 2489 * delete the last combining character. */ 2490 if (p_deco && use_delcombine && enc_utf8 2491 && utfc_ptr2len(oldp + col) >= count) 2492 { 2493 int cc[MAX_MCO]; 2494 int n; 2495 2496 (void)utfc_ptr2char(oldp + col, cc); 2497 if (cc[0] != NUL) 2498 { 2499 /* Find the last composing char, there can be several. */ 2500 n = col; 2501 do 2502 { 2503 col = n; 2504 count = utf_ptr2len(oldp + n); 2505 n += count; 2506 } while (UTF_COMPOSINGLIKE(oldp + col, oldp + n)); 2507 fixpos = 0; 2508 } 2509 } 2510 #endif 2511 2512 /* 2513 * When count is too big, reduce it. 2514 */ 2515 movelen = (long)oldlen - (long)col - count + 1; /* includes trailing NUL */ 2516 if (movelen <= 1) 2517 { 2518 /* 2519 * If we just took off the last character of a non-blank line, and 2520 * fixpos is TRUE, we don't want to end up positioned at the NUL, 2521 * unless "restart_edit" is set or 'virtualedit' contains "onemore". 2522 */ 2523 if (col > 0 && fixpos && restart_edit == 0 2524 #ifdef FEAT_VIRTUALEDIT 2525 && (ve_flags & VE_ONEMORE) == 0 2526 #endif 2527 ) 2528 { 2529 --curwin->w_cursor.col; 2530 #ifdef FEAT_VIRTUALEDIT 2531 curwin->w_cursor.coladd = 0; 2532 #endif 2533 #ifdef FEAT_MBYTE 2534 if (has_mbyte) 2535 curwin->w_cursor.col -= 2536 (*mb_head_off)(oldp, oldp + curwin->w_cursor.col); 2537 #endif 2538 } 2539 count = oldlen - col; 2540 movelen = 1; 2541 } 2542 2543 /* 2544 * If the old line has been allocated the deletion can be done in the 2545 * existing line. Otherwise a new line has to be allocated 2546 * Can't do this when using Netbeans, because we would need to invoke 2547 * netbeans_removed(), which deallocates the line. Let ml_replace() take 2548 * care of notifying Netbeans. 2549 */ 2550 #ifdef FEAT_NETBEANS_INTG 2551 if (netbeans_active()) 2552 was_alloced = FALSE; 2553 else 2554 #endif 2555 was_alloced = ml_line_alloced(); /* check if oldp was allocated */ 2556 if (was_alloced) 2557 newp = oldp; /* use same allocated memory */ 2558 else 2559 { /* need to allocate a new line */ 2560 newp = alloc((unsigned)(oldlen + 1 - count)); 2561 if (newp == NULL) 2562 return FAIL; 2563 mch_memmove(newp, oldp, (size_t)col); 2564 } 2565 mch_memmove(newp + col, oldp + col + count, (size_t)movelen); 2566 if (!was_alloced) 2567 ml_replace(lnum, newp, FALSE); 2568 2569 /* mark the buffer as changed and prepare for displaying */ 2570 changed_bytes(lnum, curwin->w_cursor.col); 2571 2572 return OK; 2573 } 2574 2575 /* 2576 * Delete from cursor to end of line. 2577 * Caller must have prepared for undo. 2578 * 2579 * return FAIL for failure, OK otherwise 2580 */ 2581 int 2582 truncate_line( 2583 int fixpos) /* if TRUE fix the cursor position when done */ 2584 { 2585 char_u *newp; 2586 linenr_T lnum = curwin->w_cursor.lnum; 2587 colnr_T col = curwin->w_cursor.col; 2588 2589 if (col == 0) 2590 newp = vim_strsave((char_u *)""); 2591 else 2592 newp = vim_strnsave(ml_get(lnum), col); 2593 2594 if (newp == NULL) 2595 return FAIL; 2596 2597 ml_replace(lnum, newp, FALSE); 2598 2599 /* mark the buffer as changed and prepare for displaying */ 2600 changed_bytes(lnum, curwin->w_cursor.col); 2601 2602 /* 2603 * If "fixpos" is TRUE we don't want to end up positioned at the NUL. 2604 */ 2605 if (fixpos && curwin->w_cursor.col > 0) 2606 --curwin->w_cursor.col; 2607 2608 return OK; 2609 } 2610 2611 /* 2612 * Delete "nlines" lines at the cursor. 2613 * Saves the lines for undo first if "undo" is TRUE. 2614 */ 2615 void 2616 del_lines( 2617 long nlines, /* number of lines to delete */ 2618 int undo) /* if TRUE, prepare for undo */ 2619 { 2620 long n; 2621 linenr_T first = curwin->w_cursor.lnum; 2622 2623 if (nlines <= 0) 2624 return; 2625 2626 /* save the deleted lines for undo */ 2627 if (undo && u_savedel(first, nlines) == FAIL) 2628 return; 2629 2630 for (n = 0; n < nlines; ) 2631 { 2632 if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to delete */ 2633 break; 2634 2635 ml_delete(first, TRUE); 2636 ++n; 2637 2638 /* If we delete the last line in the file, stop */ 2639 if (first > curbuf->b_ml.ml_line_count) 2640 break; 2641 } 2642 2643 /* Correct the cursor position before calling deleted_lines_mark(), it may 2644 * trigger a callback to display the cursor. */ 2645 curwin->w_cursor.col = 0; 2646 check_cursor_lnum(); 2647 2648 /* adjust marks, mark the buffer as changed and prepare for displaying */ 2649 deleted_lines_mark(first, n); 2650 } 2651 2652 int 2653 gchar_pos(pos_T *pos) 2654 { 2655 char_u *ptr = ml_get_pos(pos); 2656 2657 #ifdef FEAT_MBYTE 2658 if (has_mbyte) 2659 return (*mb_ptr2char)(ptr); 2660 #endif 2661 return (int)*ptr; 2662 } 2663 2664 int 2665 gchar_cursor(void) 2666 { 2667 #ifdef FEAT_MBYTE 2668 if (has_mbyte) 2669 return (*mb_ptr2char)(ml_get_cursor()); 2670 #endif 2671 return (int)*ml_get_cursor(); 2672 } 2673 2674 /* 2675 * Write a character at the current cursor position. 2676 * It is directly written into the block. 2677 */ 2678 void 2679 pchar_cursor(int c) 2680 { 2681 *(ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE) 2682 + curwin->w_cursor.col) = c; 2683 } 2684 2685 /* 2686 * When extra == 0: Return TRUE if the cursor is before or on the first 2687 * non-blank in the line. 2688 * When extra == 1: Return TRUE if the cursor is before the first non-blank in 2689 * the line. 2690 */ 2691 int 2692 inindent(int extra) 2693 { 2694 char_u *ptr; 2695 colnr_T col; 2696 2697 for (col = 0, ptr = ml_get_curline(); VIM_ISWHITE(*ptr); ++col) 2698 ++ptr; 2699 if (col >= curwin->w_cursor.col + extra) 2700 return TRUE; 2701 else 2702 return FALSE; 2703 } 2704 2705 /* 2706 * Skip to next part of an option argument: Skip space and comma. 2707 */ 2708 char_u * 2709 skip_to_option_part(char_u *p) 2710 { 2711 if (*p == ',') 2712 ++p; 2713 while (*p == ' ') 2714 ++p; 2715 return p; 2716 } 2717 2718 /* 2719 * Call this function when something in the current buffer is changed. 2720 * 2721 * Most often called through changed_bytes() and changed_lines(), which also 2722 * mark the area of the display to be redrawn. 2723 * 2724 * Careful: may trigger autocommands that reload the buffer. 2725 */ 2726 void 2727 changed(void) 2728 { 2729 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) 2730 /* The text of the preediting area is inserted, but this doesn't 2731 * mean a change of the buffer yet. That is delayed until the 2732 * text is committed. (this means preedit becomes empty) */ 2733 if (im_is_preediting() && !xim_changed_while_preediting) 2734 return; 2735 xim_changed_while_preediting = FALSE; 2736 #endif 2737 2738 if (!curbuf->b_changed) 2739 { 2740 int save_msg_scroll = msg_scroll; 2741 2742 /* Give a warning about changing a read-only file. This may also 2743 * check-out the file, thus change "curbuf"! */ 2744 change_warning(0); 2745 2746 /* Create a swap file if that is wanted. 2747 * Don't do this for "nofile" and "nowrite" buffer types. */ 2748 if (curbuf->b_may_swap 2749 #ifdef FEAT_QUICKFIX 2750 && !bt_dontwrite(curbuf) 2751 #endif 2752 ) 2753 { 2754 int save_need_wait_return = need_wait_return; 2755 2756 need_wait_return = FALSE; 2757 ml_open_file(curbuf); 2758 2759 /* The ml_open_file() can cause an ATTENTION message. 2760 * Wait two seconds, to make sure the user reads this unexpected 2761 * message. Since we could be anywhere, call wait_return() now, 2762 * and don't let the emsg() set msg_scroll. */ 2763 if (need_wait_return && emsg_silent == 0) 2764 { 2765 out_flush(); 2766 ui_delay(2000L, TRUE); 2767 wait_return(TRUE); 2768 msg_scroll = save_msg_scroll; 2769 } 2770 else 2771 need_wait_return = save_need_wait_return; 2772 } 2773 changed_int(); 2774 } 2775 ++CHANGEDTICK(curbuf); 2776 } 2777 2778 /* 2779 * Internal part of changed(), no user interaction. 2780 */ 2781 void 2782 changed_int(void) 2783 { 2784 curbuf->b_changed = TRUE; 2785 ml_setflags(curbuf); 2786 #ifdef FEAT_WINDOWS 2787 check_status(curbuf); 2788 redraw_tabline = TRUE; 2789 #endif 2790 #ifdef FEAT_TITLE 2791 need_maketitle = TRUE; /* set window title later */ 2792 #endif 2793 } 2794 2795 static void changedOneline(buf_T *buf, linenr_T lnum); 2796 static void changed_lines_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, long xtra); 2797 static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, long xtra); 2798 2799 /* 2800 * Changed bytes within a single line for the current buffer. 2801 * - marks the windows on this buffer to be redisplayed 2802 * - marks the buffer changed by calling changed() 2803 * - invalidates cached values 2804 * Careful: may trigger autocommands that reload the buffer. 2805 */ 2806 void 2807 changed_bytes(linenr_T lnum, colnr_T col) 2808 { 2809 changedOneline(curbuf, lnum); 2810 changed_common(lnum, col, lnum + 1, 0L); 2811 2812 #ifdef FEAT_DIFF 2813 /* Diff highlighting in other diff windows may need to be updated too. */ 2814 if (curwin->w_p_diff) 2815 { 2816 win_T *wp; 2817 linenr_T wlnum; 2818 2819 FOR_ALL_WINDOWS(wp) 2820 if (wp->w_p_diff && wp != curwin) 2821 { 2822 redraw_win_later(wp, VALID); 2823 wlnum = diff_lnum_win(lnum, wp); 2824 if (wlnum > 0) 2825 changedOneline(wp->w_buffer, wlnum); 2826 } 2827 } 2828 #endif 2829 } 2830 2831 static void 2832 changedOneline(buf_T *buf, linenr_T lnum) 2833 { 2834 if (buf->b_mod_set) 2835 { 2836 /* find the maximum area that must be redisplayed */ 2837 if (lnum < buf->b_mod_top) 2838 buf->b_mod_top = lnum; 2839 else if (lnum >= buf->b_mod_bot) 2840 buf->b_mod_bot = lnum + 1; 2841 } 2842 else 2843 { 2844 /* set the area that must be redisplayed to one line */ 2845 buf->b_mod_set = TRUE; 2846 buf->b_mod_top = lnum; 2847 buf->b_mod_bot = lnum + 1; 2848 buf->b_mod_xlines = 0; 2849 } 2850 } 2851 2852 /* 2853 * Appended "count" lines below line "lnum" in the current buffer. 2854 * Must be called AFTER the change and after mark_adjust(). 2855 * Takes care of marking the buffer to be redrawn and sets the changed flag. 2856 */ 2857 void 2858 appended_lines(linenr_T lnum, long count) 2859 { 2860 changed_lines(lnum + 1, 0, lnum + 1, count); 2861 } 2862 2863 /* 2864 * Like appended_lines(), but adjust marks first. 2865 */ 2866 void 2867 appended_lines_mark(linenr_T lnum, long count) 2868 { 2869 /* Skip mark_adjust when adding a line after the last one, there can't 2870 * be marks there. But it's still needed in diff mode. */ 2871 if (lnum + count < curbuf->b_ml.ml_line_count 2872 #ifdef FEAT_DIFF 2873 || curwin->w_p_diff 2874 #endif 2875 ) 2876 mark_adjust(lnum + 1, (linenr_T)MAXLNUM, count, 0L); 2877 changed_lines(lnum + 1, 0, lnum + 1, count); 2878 } 2879 2880 /* 2881 * Deleted "count" lines at line "lnum" in the current buffer. 2882 * Must be called AFTER the change and after mark_adjust(). 2883 * Takes care of marking the buffer to be redrawn and sets the changed flag. 2884 */ 2885 void 2886 deleted_lines(linenr_T lnum, long count) 2887 { 2888 changed_lines(lnum, 0, lnum + count, -count); 2889 } 2890 2891 /* 2892 * Like deleted_lines(), but adjust marks first. 2893 * Make sure the cursor is on a valid line before calling, a GUI callback may 2894 * be triggered to display the cursor. 2895 */ 2896 void 2897 deleted_lines_mark(linenr_T lnum, long count) 2898 { 2899 mark_adjust(lnum, (linenr_T)(lnum + count - 1), (long)MAXLNUM, -count); 2900 changed_lines(lnum, 0, lnum + count, -count); 2901 } 2902 2903 /* 2904 * Changed lines for the current buffer. 2905 * Must be called AFTER the change and after mark_adjust(). 2906 * - mark the buffer changed by calling changed() 2907 * - mark the windows on this buffer to be redisplayed 2908 * - invalidate cached values 2909 * "lnum" is the first line that needs displaying, "lnume" the first line 2910 * below the changed lines (BEFORE the change). 2911 * When only inserting lines, "lnum" and "lnume" are equal. 2912 * Takes care of calling changed() and updating b_mod_*. 2913 * Careful: may trigger autocommands that reload the buffer. 2914 */ 2915 void 2916 changed_lines( 2917 linenr_T lnum, /* first line with change */ 2918 colnr_T col, /* column in first line with change */ 2919 linenr_T lnume, /* line below last changed line */ 2920 long xtra) /* number of extra lines (negative when deleting) */ 2921 { 2922 changed_lines_buf(curbuf, lnum, lnume, xtra); 2923 2924 #ifdef FEAT_DIFF 2925 if (xtra == 0 && curwin->w_p_diff) 2926 { 2927 /* When the number of lines doesn't change then mark_adjust() isn't 2928 * called and other diff buffers still need to be marked for 2929 * displaying. */ 2930 win_T *wp; 2931 linenr_T wlnum; 2932 2933 FOR_ALL_WINDOWS(wp) 2934 if (wp->w_p_diff && wp != curwin) 2935 { 2936 redraw_win_later(wp, VALID); 2937 wlnum = diff_lnum_win(lnum, wp); 2938 if (wlnum > 0) 2939 changed_lines_buf(wp->w_buffer, wlnum, 2940 lnume - lnum + wlnum, 0L); 2941 } 2942 } 2943 #endif 2944 2945 changed_common(lnum, col, lnume, xtra); 2946 } 2947 2948 static void 2949 changed_lines_buf( 2950 buf_T *buf, 2951 linenr_T lnum, /* first line with change */ 2952 linenr_T lnume, /* line below last changed line */ 2953 long xtra) /* number of extra lines (negative when deleting) */ 2954 { 2955 if (buf->b_mod_set) 2956 { 2957 /* find the maximum area that must be redisplayed */ 2958 if (lnum < buf->b_mod_top) 2959 buf->b_mod_top = lnum; 2960 if (lnum < buf->b_mod_bot) 2961 { 2962 /* adjust old bot position for xtra lines */ 2963 buf->b_mod_bot += xtra; 2964 if (buf->b_mod_bot < lnum) 2965 buf->b_mod_bot = lnum; 2966 } 2967 if (lnume + xtra > buf->b_mod_bot) 2968 buf->b_mod_bot = lnume + xtra; 2969 buf->b_mod_xlines += xtra; 2970 } 2971 else 2972 { 2973 /* set the area that must be redisplayed */ 2974 buf->b_mod_set = TRUE; 2975 buf->b_mod_top = lnum; 2976 buf->b_mod_bot = lnume + xtra; 2977 buf->b_mod_xlines = xtra; 2978 } 2979 } 2980 2981 /* 2982 * Common code for when a change is was made. 2983 * See changed_lines() for the arguments. 2984 * Careful: may trigger autocommands that reload the buffer. 2985 */ 2986 static void 2987 changed_common( 2988 linenr_T lnum, 2989 colnr_T col, 2990 linenr_T lnume, 2991 long xtra) 2992 { 2993 win_T *wp; 2994 #ifdef FEAT_WINDOWS 2995 tabpage_T *tp; 2996 #endif 2997 int i; 2998 #ifdef FEAT_JUMPLIST 2999 int cols; 3000 pos_T *p; 3001 int add; 3002 #endif 3003 3004 /* mark the buffer as modified */ 3005 changed(); 3006 3007 /* set the '. mark */ 3008 if (!cmdmod.keepjumps) 3009 { 3010 curbuf->b_last_change.lnum = lnum; 3011 curbuf->b_last_change.col = col; 3012 3013 #ifdef FEAT_JUMPLIST 3014 /* Create a new entry if a new undo-able change was started or we 3015 * don't have an entry yet. */ 3016 if (curbuf->b_new_change || curbuf->b_changelistlen == 0) 3017 { 3018 if (curbuf->b_changelistlen == 0) 3019 add = TRUE; 3020 else 3021 { 3022 /* Don't create a new entry when the line number is the same 3023 * as the last one and the column is not too far away. Avoids 3024 * creating many entries for typing "xxxxx". */ 3025 p = &curbuf->b_changelist[curbuf->b_changelistlen - 1]; 3026 if (p->lnum != lnum) 3027 add = TRUE; 3028 else 3029 { 3030 cols = comp_textwidth(FALSE); 3031 if (cols == 0) 3032 cols = 79; 3033 add = (p->col + cols < col || col + cols < p->col); 3034 } 3035 } 3036 if (add) 3037 { 3038 /* This is the first of a new sequence of undo-able changes 3039 * and it's at some distance of the last change. Use a new 3040 * position in the changelist. */ 3041 curbuf->b_new_change = FALSE; 3042 3043 if (curbuf->b_changelistlen == JUMPLISTSIZE) 3044 { 3045 /* changelist is full: remove oldest entry */ 3046 curbuf->b_changelistlen = JUMPLISTSIZE - 1; 3047 mch_memmove(curbuf->b_changelist, curbuf->b_changelist + 1, 3048 sizeof(pos_T) * (JUMPLISTSIZE - 1)); 3049 FOR_ALL_TAB_WINDOWS(tp, wp) 3050 { 3051 /* Correct position in changelist for other windows on 3052 * this buffer. */ 3053 if (wp->w_buffer == curbuf && wp->w_changelistidx > 0) 3054 --wp->w_changelistidx; 3055 } 3056 } 3057 FOR_ALL_TAB_WINDOWS(tp, wp) 3058 { 3059 /* For other windows, if the position in the changelist is 3060 * at the end it stays at the end. */ 3061 if (wp->w_buffer == curbuf 3062 && wp->w_changelistidx == curbuf->b_changelistlen) 3063 ++wp->w_changelistidx; 3064 } 3065 ++curbuf->b_changelistlen; 3066 } 3067 } 3068 curbuf->b_changelist[curbuf->b_changelistlen - 1] = 3069 curbuf->b_last_change; 3070 /* The current window is always after the last change, so that "g," 3071 * takes you back to it. */ 3072 curwin->w_changelistidx = curbuf->b_changelistlen; 3073 #endif 3074 } 3075 3076 FOR_ALL_TAB_WINDOWS(tp, wp) 3077 { 3078 if (wp->w_buffer == curbuf) 3079 { 3080 /* Mark this window to be redrawn later. */ 3081 if (wp->w_redr_type < VALID) 3082 wp->w_redr_type = VALID; 3083 3084 /* Check if a change in the buffer has invalidated the cached 3085 * values for the cursor. */ 3086 #ifdef FEAT_FOLDING 3087 /* 3088 * Update the folds for this window. Can't postpone this, because 3089 * a following operator might work on the whole fold: ">>dd". 3090 */ 3091 foldUpdate(wp, lnum, lnume + xtra - 1); 3092 3093 /* The change may cause lines above or below the change to become 3094 * included in a fold. Set lnum/lnume to the first/last line that 3095 * might be displayed differently. 3096 * Set w_cline_folded here as an efficient way to update it when 3097 * inserting lines just above a closed fold. */ 3098 i = hasFoldingWin(wp, lnum, &lnum, NULL, FALSE, NULL); 3099 if (wp->w_cursor.lnum == lnum) 3100 wp->w_cline_folded = i; 3101 i = hasFoldingWin(wp, lnume, NULL, &lnume, FALSE, NULL); 3102 if (wp->w_cursor.lnum == lnume) 3103 wp->w_cline_folded = i; 3104 3105 /* If the changed line is in a range of previously folded lines, 3106 * compare with the first line in that range. */ 3107 if (wp->w_cursor.lnum <= lnum) 3108 { 3109 i = find_wl_entry(wp, lnum); 3110 if (i >= 0 && wp->w_cursor.lnum > wp->w_lines[i].wl_lnum) 3111 changed_line_abv_curs_win(wp); 3112 } 3113 #endif 3114 3115 if (wp->w_cursor.lnum > lnum) 3116 changed_line_abv_curs_win(wp); 3117 else if (wp->w_cursor.lnum == lnum && wp->w_cursor.col >= col) 3118 changed_cline_bef_curs_win(wp); 3119 if (wp->w_botline >= lnum) 3120 { 3121 /* Assume that botline doesn't change (inserted lines make 3122 * other lines scroll down below botline). */ 3123 approximate_botline_win(wp); 3124 } 3125 3126 /* Check if any w_lines[] entries have become invalid. 3127 * For entries below the change: Correct the lnums for 3128 * inserted/deleted lines. Makes it possible to stop displaying 3129 * after the change. */ 3130 for (i = 0; i < wp->w_lines_valid; ++i) 3131 if (wp->w_lines[i].wl_valid) 3132 { 3133 if (wp->w_lines[i].wl_lnum >= lnum) 3134 { 3135 if (wp->w_lines[i].wl_lnum < lnume) 3136 { 3137 /* line included in change */ 3138 wp->w_lines[i].wl_valid = FALSE; 3139 } 3140 else if (xtra != 0) 3141 { 3142 /* line below change */ 3143 wp->w_lines[i].wl_lnum += xtra; 3144 #ifdef FEAT_FOLDING 3145 wp->w_lines[i].wl_lastlnum += xtra; 3146 #endif 3147 } 3148 } 3149 #ifdef FEAT_FOLDING 3150 else if (wp->w_lines[i].wl_lastlnum >= lnum) 3151 { 3152 /* change somewhere inside this range of folded lines, 3153 * may need to be redrawn */ 3154 wp->w_lines[i].wl_valid = FALSE; 3155 } 3156 #endif 3157 } 3158 3159 #ifdef FEAT_FOLDING 3160 /* Take care of side effects for setting w_topline when folds have 3161 * changed. Esp. when the buffer was changed in another window. */ 3162 if (hasAnyFolding(wp)) 3163 set_topline(wp, wp->w_topline); 3164 #endif 3165 /* relative numbering may require updating more */ 3166 if (wp->w_p_rnu) 3167 redraw_win_later(wp, SOME_VALID); 3168 } 3169 } 3170 3171 /* Call update_screen() later, which checks out what needs to be redrawn, 3172 * since it notices b_mod_set and then uses b_mod_*. */ 3173 if (must_redraw < VALID) 3174 must_redraw = VALID; 3175 3176 #ifdef FEAT_AUTOCMD 3177 /* when the cursor line is changed always trigger CursorMoved */ 3178 if (lnum <= curwin->w_cursor.lnum 3179 && lnume + (xtra < 0 ? -xtra : xtra) > curwin->w_cursor.lnum) 3180 last_cursormoved.lnum = 0; 3181 #endif 3182 } 3183 3184 /* 3185 * unchanged() is called when the changed flag must be reset for buffer 'buf' 3186 */ 3187 void 3188 unchanged( 3189 buf_T *buf, 3190 int ff) /* also reset 'fileformat' */ 3191 { 3192 if (buf->b_changed || (ff && file_ff_differs(buf, FALSE))) 3193 { 3194 buf->b_changed = 0; 3195 ml_setflags(buf); 3196 if (ff) 3197 save_file_ff(buf); 3198 #ifdef FEAT_WINDOWS 3199 check_status(buf); 3200 redraw_tabline = TRUE; 3201 #endif 3202 #ifdef FEAT_TITLE 3203 need_maketitle = TRUE; /* set window title later */ 3204 #endif 3205 } 3206 ++CHANGEDTICK(buf); 3207 #ifdef FEAT_NETBEANS_INTG 3208 netbeans_unmodified(buf); 3209 #endif 3210 } 3211 3212 #if defined(FEAT_WINDOWS) || defined(PROTO) 3213 /* 3214 * check_status: called when the status bars for the buffer 'buf' 3215 * need to be updated 3216 */ 3217 void 3218 check_status(buf_T *buf) 3219 { 3220 win_T *wp; 3221 3222 FOR_ALL_WINDOWS(wp) 3223 if (wp->w_buffer == buf && wp->w_status_height) 3224 { 3225 wp->w_redr_status = TRUE; 3226 if (must_redraw < VALID) 3227 must_redraw = VALID; 3228 } 3229 } 3230 #endif 3231 3232 /* 3233 * If the file is readonly, give a warning message with the first change. 3234 * Don't do this for autocommands. 3235 * Don't use emsg(), because it flushes the macro buffer. 3236 * If we have undone all changes b_changed will be FALSE, but "b_did_warn" 3237 * will be TRUE. 3238 * Careful: may trigger autocommands that reload the buffer. 3239 */ 3240 void 3241 change_warning( 3242 int col) /* column for message; non-zero when in insert 3243 mode and 'showmode' is on */ 3244 { 3245 static char *w_readonly = N_("W10: Warning: Changing a readonly file"); 3246 3247 if (curbuf->b_did_warn == FALSE 3248 && curbufIsChanged() == 0 3249 #ifdef FEAT_AUTOCMD 3250 && !autocmd_busy 3251 #endif 3252 && curbuf->b_p_ro) 3253 { 3254 #ifdef FEAT_AUTOCMD 3255 ++curbuf_lock; 3256 apply_autocmds(EVENT_FILECHANGEDRO, NULL, NULL, FALSE, curbuf); 3257 --curbuf_lock; 3258 if (!curbuf->b_p_ro) 3259 return; 3260 #endif 3261 /* 3262 * Do what msg() does, but with a column offset if the warning should 3263 * be after the mode message. 3264 */ 3265 msg_start(); 3266 if (msg_row == Rows - 1) 3267 msg_col = col; 3268 msg_source(HL_ATTR(HLF_W)); 3269 MSG_PUTS_ATTR(_(w_readonly), HL_ATTR(HLF_W) | MSG_HIST); 3270 #ifdef FEAT_EVAL 3271 set_vim_var_string(VV_WARNINGMSG, (char_u *)_(w_readonly), -1); 3272 #endif 3273 msg_clr_eos(); 3274 (void)msg_end(); 3275 if (msg_silent == 0 && !silent_mode 3276 #ifdef FEAT_EVAL 3277 && time_for_testing != 1 3278 #endif 3279 ) 3280 { 3281 out_flush(); 3282 ui_delay(1000L, TRUE); /* give the user time to think about it */ 3283 } 3284 curbuf->b_did_warn = TRUE; 3285 redraw_cmdline = FALSE; /* don't redraw and erase the message */ 3286 if (msg_row < Rows - 1) 3287 showmode(); 3288 } 3289 } 3290 3291 /* 3292 * Ask for a reply from the user, a 'y' or a 'n'. 3293 * No other characters are accepted, the message is repeated until a valid 3294 * reply is entered or CTRL-C is hit. 3295 * If direct is TRUE, don't use vgetc() but ui_inchar(), don't get characters 3296 * from any buffers but directly from the user. 3297 * 3298 * return the 'y' or 'n' 3299 */ 3300 int 3301 ask_yesno(char_u *str, int direct) 3302 { 3303 int r = ' '; 3304 int save_State = State; 3305 3306 if (exiting) /* put terminal in raw mode for this question */ 3307 settmode(TMODE_RAW); 3308 ++no_wait_return; 3309 #ifdef USE_ON_FLY_SCROLL 3310 dont_scroll = TRUE; /* disallow scrolling here */ 3311 #endif 3312 State = CONFIRM; /* mouse behaves like with :confirm */ 3313 #ifdef FEAT_MOUSE 3314 setmouse(); /* disables mouse for xterm */ 3315 #endif 3316 ++no_mapping; 3317 ++allow_keys; /* no mapping here, but recognize keys */ 3318 3319 while (r != 'y' && r != 'n') 3320 { 3321 /* same highlighting as for wait_return */ 3322 smsg_attr(HL_ATTR(HLF_R), (char_u *)"%s (y/n)?", str); 3323 if (direct) 3324 r = get_keystroke(); 3325 else 3326 r = plain_vgetc(); 3327 if (r == Ctrl_C || r == ESC) 3328 r = 'n'; 3329 msg_putchar(r); /* show what you typed */ 3330 out_flush(); 3331 } 3332 --no_wait_return; 3333 State = save_State; 3334 #ifdef FEAT_MOUSE 3335 setmouse(); 3336 #endif 3337 --no_mapping; 3338 --allow_keys; 3339 3340 return r; 3341 } 3342 3343 #if defined(FEAT_MOUSE) || defined(PROTO) 3344 /* 3345 * Return TRUE if "c" is a mouse key. 3346 */ 3347 int 3348 is_mouse_key(int c) 3349 { 3350 return c == K_LEFTMOUSE 3351 || c == K_LEFTMOUSE_NM 3352 || c == K_LEFTDRAG 3353 || c == K_LEFTRELEASE 3354 || c == K_LEFTRELEASE_NM 3355 || c == K_MIDDLEMOUSE 3356 || c == K_MIDDLEDRAG 3357 || c == K_MIDDLERELEASE 3358 || c == K_RIGHTMOUSE 3359 || c == K_RIGHTDRAG 3360 || c == K_RIGHTRELEASE 3361 || c == K_MOUSEDOWN 3362 || c == K_MOUSEUP 3363 || c == K_MOUSELEFT 3364 || c == K_MOUSERIGHT 3365 || c == K_X1MOUSE 3366 || c == K_X1DRAG 3367 || c == K_X1RELEASE 3368 || c == K_X2MOUSE 3369 || c == K_X2DRAG 3370 || c == K_X2RELEASE; 3371 } 3372 #endif 3373 3374 /* 3375 * Get a key stroke directly from the user. 3376 * Ignores mouse clicks and scrollbar events, except a click for the left 3377 * button (used at the more prompt). 3378 * Doesn't use vgetc(), because it syncs undo and eats mapped characters. 3379 * Disadvantage: typeahead is ignored. 3380 * Translates the interrupt character for unix to ESC. 3381 */ 3382 int 3383 get_keystroke(void) 3384 { 3385 char_u *buf = NULL; 3386 int buflen = 150; 3387 int maxlen; 3388 int len = 0; 3389 int n; 3390 int save_mapped_ctrl_c = mapped_ctrl_c; 3391 int waited = 0; 3392 3393 mapped_ctrl_c = FALSE; /* mappings are not used here */ 3394 for (;;) 3395 { 3396 cursor_on(); 3397 out_flush(); 3398 3399 /* Leave some room for check_termcode() to insert a key code into (max 3400 * 5 chars plus NUL). And fix_input_buffer() can triple the number of 3401 * bytes. */ 3402 maxlen = (buflen - 6 - len) / 3; 3403 if (buf == NULL) 3404 buf = alloc(buflen); 3405 else if (maxlen < 10) 3406 { 3407 char_u *t_buf = buf; 3408 3409 /* Need some more space. This might happen when receiving a long 3410 * escape sequence. */ 3411 buflen += 100; 3412 buf = vim_realloc(buf, buflen); 3413 if (buf == NULL) 3414 vim_free(t_buf); 3415 maxlen = (buflen - 6 - len) / 3; 3416 } 3417 if (buf == NULL) 3418 { 3419 do_outofmem_msg((long_u)buflen); 3420 return ESC; /* panic! */ 3421 } 3422 3423 /* First time: blocking wait. Second time: wait up to 100ms for a 3424 * terminal code to complete. */ 3425 n = ui_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0); 3426 if (n > 0) 3427 { 3428 /* Replace zero and CSI by a special key code. */ 3429 n = fix_input_buffer(buf + len, n); 3430 len += n; 3431 waited = 0; 3432 } 3433 else if (len > 0) 3434 ++waited; /* keep track of the waiting time */ 3435 3436 /* Incomplete termcode and not timed out yet: get more characters */ 3437 if ((n = check_termcode(1, buf, buflen, &len)) < 0 3438 && (!p_ttimeout || waited * 100L < (p_ttm < 0 ? p_tm : p_ttm))) 3439 continue; 3440 3441 if (n == KEYLEN_REMOVED) /* key code removed */ 3442 { 3443 if (must_redraw != 0 && !need_wait_return && (State & CMDLINE) == 0) 3444 { 3445 /* Redrawing was postponed, do it now. */ 3446 update_screen(0); 3447 setcursor(); /* put cursor back where it belongs */ 3448 } 3449 continue; 3450 } 3451 if (n > 0) /* found a termcode: adjust length */ 3452 len = n; 3453 if (len == 0) /* nothing typed yet */ 3454 continue; 3455 3456 /* Handle modifier and/or special key code. */ 3457 n = buf[0]; 3458 if (n == K_SPECIAL) 3459 { 3460 n = TO_SPECIAL(buf[1], buf[2]); 3461 if (buf[1] == KS_MODIFIER 3462 || n == K_IGNORE 3463 #ifdef FEAT_MOUSE 3464 || (is_mouse_key(n) && n != K_LEFTMOUSE) 3465 #endif 3466 #ifdef FEAT_GUI 3467 || n == K_VER_SCROLLBAR 3468 || n == K_HOR_SCROLLBAR 3469 #endif 3470 ) 3471 { 3472 if (buf[1] == KS_MODIFIER) 3473 mod_mask = buf[2]; 3474 len -= 3; 3475 if (len > 0) 3476 mch_memmove(buf, buf + 3, (size_t)len); 3477 continue; 3478 } 3479 break; 3480 } 3481 #ifdef FEAT_MBYTE 3482 if (has_mbyte) 3483 { 3484 if (MB_BYTE2LEN(n) > len) 3485 continue; /* more bytes to get */ 3486 buf[len >= buflen ? buflen - 1 : len] = NUL; 3487 n = (*mb_ptr2char)(buf); 3488 } 3489 #endif 3490 #ifdef UNIX 3491 if (n == intr_char) 3492 n = ESC; 3493 #endif 3494 break; 3495 } 3496 vim_free(buf); 3497 3498 mapped_ctrl_c = save_mapped_ctrl_c; 3499 return n; 3500 } 3501 3502 /* 3503 * Get a number from the user. 3504 * When "mouse_used" is not NULL allow using the mouse. 3505 */ 3506 int 3507 get_number( 3508 int colon, /* allow colon to abort */ 3509 int *mouse_used) 3510 { 3511 int n = 0; 3512 int c; 3513 int typed = 0; 3514 3515 if (mouse_used != NULL) 3516 *mouse_used = FALSE; 3517 3518 /* When not printing messages, the user won't know what to type, return a 3519 * zero (as if CR was hit). */ 3520 if (msg_silent != 0) 3521 return 0; 3522 3523 #ifdef USE_ON_FLY_SCROLL 3524 dont_scroll = TRUE; /* disallow scrolling here */ 3525 #endif 3526 ++no_mapping; 3527 ++allow_keys; /* no mapping here, but recognize keys */ 3528 for (;;) 3529 { 3530 windgoto(msg_row, msg_col); 3531 c = safe_vgetc(); 3532 if (VIM_ISDIGIT(c)) 3533 { 3534 n = n * 10 + c - '0'; 3535 msg_putchar(c); 3536 ++typed; 3537 } 3538 else if (c == K_DEL || c == K_KDEL || c == K_BS || c == Ctrl_H) 3539 { 3540 if (typed > 0) 3541 { 3542 MSG_PUTS("\b \b"); 3543 --typed; 3544 } 3545 n /= 10; 3546 } 3547 #ifdef FEAT_MOUSE 3548 else if (mouse_used != NULL && c == K_LEFTMOUSE) 3549 { 3550 *mouse_used = TRUE; 3551 n = mouse_row + 1; 3552 break; 3553 } 3554 #endif 3555 else if (n == 0 && c == ':' && colon) 3556 { 3557 stuffcharReadbuff(':'); 3558 if (!exmode_active) 3559 cmdline_row = msg_row; 3560 skip_redraw = TRUE; /* skip redraw once */ 3561 do_redraw = FALSE; 3562 break; 3563 } 3564 else if (c == CAR || c == NL || c == Ctrl_C || c == ESC) 3565 break; 3566 } 3567 --no_mapping; 3568 --allow_keys; 3569 return n; 3570 } 3571 3572 /* 3573 * Ask the user to enter a number. 3574 * When "mouse_used" is not NULL allow using the mouse and in that case return 3575 * the line number. 3576 */ 3577 int 3578 prompt_for_number(int *mouse_used) 3579 { 3580 int i; 3581 int save_cmdline_row; 3582 int save_State; 3583 3584 /* When using ":silent" assume that <CR> was entered. */ 3585 if (mouse_used != NULL) 3586 MSG_PUTS(_("Type number and <Enter> or click with mouse (empty cancels): ")); 3587 else 3588 MSG_PUTS(_("Type number and <Enter> (empty cancels): ")); 3589 3590 /* Set the state such that text can be selected/copied/pasted and we still 3591 * get mouse events. */ 3592 save_cmdline_row = cmdline_row; 3593 cmdline_row = 0; 3594 save_State = State; 3595 State = ASKMORE; /* prevents a screen update when using a timer */ 3596 3597 i = get_number(TRUE, mouse_used); 3598 if (KeyTyped) 3599 { 3600 /* don't call wait_return() now */ 3601 /* msg_putchar('\n'); */ 3602 cmdline_row = msg_row - 1; 3603 need_wait_return = FALSE; 3604 msg_didany = FALSE; 3605 msg_didout = FALSE; 3606 } 3607 else 3608 cmdline_row = save_cmdline_row; 3609 State = save_State; 3610 3611 return i; 3612 } 3613 3614 void 3615 msgmore(long n) 3616 { 3617 long pn; 3618 3619 if (global_busy /* no messages now, wait until global is finished */ 3620 || !messaging()) /* 'lazyredraw' set, don't do messages now */ 3621 return; 3622 3623 /* We don't want to overwrite another important message, but do overwrite 3624 * a previous "more lines" or "fewer lines" message, so that "5dd" and 3625 * then "put" reports the last action. */ 3626 if (keep_msg != NULL && !keep_msg_more) 3627 return; 3628 3629 if (n > 0) 3630 pn = n; 3631 else 3632 pn = -n; 3633 3634 if (pn > p_report) 3635 { 3636 if (pn == 1) 3637 { 3638 if (n > 0) 3639 vim_strncpy(msg_buf, (char_u *)_("1 more line"), 3640 MSG_BUF_LEN - 1); 3641 else 3642 vim_strncpy(msg_buf, (char_u *)_("1 line less"), 3643 MSG_BUF_LEN - 1); 3644 } 3645 else 3646 { 3647 if (n > 0) 3648 vim_snprintf((char *)msg_buf, MSG_BUF_LEN, 3649 _("%ld more lines"), pn); 3650 else 3651 vim_snprintf((char *)msg_buf, MSG_BUF_LEN, 3652 _("%ld fewer lines"), pn); 3653 } 3654 if (got_int) 3655 vim_strcat(msg_buf, (char_u *)_(" (Interrupted)"), MSG_BUF_LEN); 3656 if (msg(msg_buf)) 3657 { 3658 set_keep_msg(msg_buf, 0); 3659 keep_msg_more = TRUE; 3660 } 3661 } 3662 } 3663 3664 /* 3665 * flush map and typeahead buffers and give a warning for an error 3666 */ 3667 void 3668 beep_flush(void) 3669 { 3670 if (emsg_silent == 0) 3671 { 3672 flush_buffers(FALSE); 3673 vim_beep(BO_ERROR); 3674 } 3675 } 3676 3677 /* 3678 * Give a warning for an error. 3679 */ 3680 void 3681 vim_beep( 3682 unsigned val) /* one of the BO_ values, e.g., BO_OPER */ 3683 { 3684 if (emsg_silent == 0) 3685 { 3686 if (!((bo_flags & val) || (bo_flags & BO_ALL))) 3687 { 3688 #ifdef ELAPSED_FUNC 3689 static int did_init = FALSE; 3690 static ELAPSED_TYPE start_tv; 3691 3692 /* Only beep once per half a second, otherwise a sequence of beeps 3693 * would freeze Vim. */ 3694 if (!did_init || ELAPSED_FUNC(start_tv) > 500) 3695 { 3696 did_init = TRUE; 3697 ELAPSED_INIT(start_tv); 3698 #endif 3699 if (p_vb 3700 #ifdef FEAT_GUI 3701 /* While the GUI is starting up the termcap is set for 3702 * the GUI but the output still goes to a terminal. */ 3703 && !(gui.in_use && gui.starting) 3704 #endif 3705 ) 3706 out_str_cf(T_VB); 3707 else 3708 out_char(BELL); 3709 #ifdef ELAPSED_FUNC 3710 } 3711 #endif 3712 } 3713 3714 /* When 'verbose' is set and we are sourcing a script or executing a 3715 * function give the user a hint where the beep comes from. */ 3716 if (vim_strchr(p_debug, 'e') != NULL) 3717 { 3718 msg_source(HL_ATTR(HLF_W)); 3719 msg_attr((char_u *)_("Beep!"), HL_ATTR(HLF_W)); 3720 } 3721 } 3722 } 3723 3724 /* 3725 * To get the "real" home directory: 3726 * - get value of $HOME 3727 * For Unix: 3728 * - go to that directory 3729 * - do mch_dirname() to get the real name of that directory. 3730 * This also works with mounts and links. 3731 * Don't do this for MS-DOS, it will change the "current dir" for a drive. 3732 */ 3733 static char_u *homedir = NULL; 3734 3735 void 3736 init_homedir(void) 3737 { 3738 char_u *var; 3739 3740 /* In case we are called a second time (when 'encoding' changes). */ 3741 vim_free(homedir); 3742 homedir = NULL; 3743 3744 #ifdef VMS 3745 var = mch_getenv((char_u *)"SYS$LOGIN"); 3746 #else 3747 var = mch_getenv((char_u *)"HOME"); 3748 #endif 3749 3750 if (var != NULL && *var == NUL) /* empty is same as not set */ 3751 var = NULL; 3752 3753 #ifdef WIN3264 3754 /* 3755 * Weird but true: $HOME may contain an indirect reference to another 3756 * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set 3757 * when $HOME is being set. 3758 */ 3759 if (var != NULL && *var == '%') 3760 { 3761 char_u *p; 3762 char_u *exp; 3763 3764 p = vim_strchr(var + 1, '%'); 3765 if (p != NULL) 3766 { 3767 vim_strncpy(NameBuff, var + 1, p - (var + 1)); 3768 exp = mch_getenv(NameBuff); 3769 if (exp != NULL && *exp != NUL 3770 && STRLEN(exp) + STRLEN(p) < MAXPATHL) 3771 { 3772 vim_snprintf((char *)NameBuff, MAXPATHL, "%s%s", exp, p + 1); 3773 var = NameBuff; 3774 /* Also set $HOME, it's needed for _viminfo. */ 3775 vim_setenv((char_u *)"HOME", NameBuff); 3776 } 3777 } 3778 } 3779 3780 /* 3781 * Typically, $HOME is not defined on Windows, unless the user has 3782 * specifically defined it for Vim's sake. However, on Windows NT 3783 * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for 3784 * each user. Try constructing $HOME from these. 3785 */ 3786 if (var == NULL) 3787 { 3788 char_u *homedrive, *homepath; 3789 3790 homedrive = mch_getenv((char_u *)"HOMEDRIVE"); 3791 homepath = mch_getenv((char_u *)"HOMEPATH"); 3792 if (homepath == NULL || *homepath == NUL) 3793 homepath = (char_u *)"\\"; 3794 if (homedrive != NULL 3795 && STRLEN(homedrive) + STRLEN(homepath) < MAXPATHL) 3796 { 3797 sprintf((char *)NameBuff, "%s%s", homedrive, homepath); 3798 if (NameBuff[0] != NUL) 3799 { 3800 var = NameBuff; 3801 /* Also set $HOME, it's needed for _viminfo. */ 3802 vim_setenv((char_u *)"HOME", NameBuff); 3803 } 3804 } 3805 } 3806 3807 # if defined(FEAT_MBYTE) 3808 if (enc_utf8 && var != NULL) 3809 { 3810 int len; 3811 char_u *pp = NULL; 3812 3813 /* Convert from active codepage to UTF-8. Other conversions are 3814 * not done, because they would fail for non-ASCII characters. */ 3815 acp_to_enc(var, (int)STRLEN(var), &pp, &len); 3816 if (pp != NULL) 3817 { 3818 homedir = pp; 3819 return; 3820 } 3821 } 3822 # endif 3823 #endif 3824 3825 #if defined(MSWIN) 3826 /* 3827 * Default home dir is C:/ 3828 * Best assumption we can make in such a situation. 3829 */ 3830 if (var == NULL) 3831 var = (char_u *)"C:/"; 3832 #endif 3833 if (var != NULL) 3834 { 3835 #ifdef UNIX 3836 /* 3837 * Change to the directory and get the actual path. This resolves 3838 * links. Don't do it when we can't return. 3839 */ 3840 if (mch_dirname(NameBuff, MAXPATHL) == OK 3841 && mch_chdir((char *)NameBuff) == 0) 3842 { 3843 if (!mch_chdir((char *)var) && mch_dirname(IObuff, IOSIZE) == OK) 3844 var = IObuff; 3845 if (mch_chdir((char *)NameBuff) != 0) 3846 EMSG(_(e_prev_dir)); 3847 } 3848 #endif 3849 homedir = vim_strsave(var); 3850 } 3851 } 3852 3853 #if defined(EXITFREE) || defined(PROTO) 3854 void 3855 free_homedir(void) 3856 { 3857 vim_free(homedir); 3858 } 3859 3860 # ifdef FEAT_CMDL_COMPL 3861 void 3862 free_users(void) 3863 { 3864 ga_clear_strings(&ga_users); 3865 } 3866 # endif 3867 #endif 3868 3869 /* 3870 * Call expand_env() and store the result in an allocated string. 3871 * This is not very memory efficient, this expects the result to be freed 3872 * again soon. 3873 */ 3874 char_u * 3875 expand_env_save(char_u *src) 3876 { 3877 return expand_env_save_opt(src, FALSE); 3878 } 3879 3880 /* 3881 * Idem, but when "one" is TRUE handle the string as one file name, only 3882 * expand "~" at the start. 3883 */ 3884 char_u * 3885 expand_env_save_opt(char_u *src, int one) 3886 { 3887 char_u *p; 3888 3889 p = alloc(MAXPATHL); 3890 if (p != NULL) 3891 expand_env_esc(src, p, MAXPATHL, FALSE, one, NULL); 3892 return p; 3893 } 3894 3895 /* 3896 * Expand environment variable with path name. 3897 * "~/" is also expanded, using $HOME. For Unix "~user/" is expanded. 3898 * Skips over "\ ", "\~" and "\$" (not for Win32 though). 3899 * If anything fails no expansion is done and dst equals src. 3900 */ 3901 void 3902 expand_env( 3903 char_u *src, /* input string e.g. "$HOME/vim.hlp" */ 3904 char_u *dst, /* where to put the result */ 3905 int dstlen) /* maximum length of the result */ 3906 { 3907 expand_env_esc(src, dst, dstlen, FALSE, FALSE, NULL); 3908 } 3909 3910 void 3911 expand_env_esc( 3912 char_u *srcp, /* input string e.g. "$HOME/vim.hlp" */ 3913 char_u *dst, /* where to put the result */ 3914 int dstlen, /* maximum length of the result */ 3915 int esc, /* escape spaces in expanded variables */ 3916 int one, /* "srcp" is one file name */ 3917 char_u *startstr) /* start again after this (can be NULL) */ 3918 { 3919 char_u *src; 3920 char_u *tail; 3921 int c; 3922 char_u *var; 3923 int copy_char; 3924 int mustfree; /* var was allocated, need to free it later */ 3925 int at_start = TRUE; /* at start of a name */ 3926 int startstr_len = 0; 3927 3928 if (startstr != NULL) 3929 startstr_len = (int)STRLEN(startstr); 3930 3931 src = skipwhite(srcp); 3932 --dstlen; /* leave one char space for "\," */ 3933 while (*src && dstlen > 0) 3934 { 3935 #ifdef FEAT_EVAL 3936 /* Skip over `=expr`. */ 3937 if (src[0] == '`' && src[1] == '=') 3938 { 3939 size_t len; 3940 3941 var = src; 3942 src += 2; 3943 (void)skip_expr(&src); 3944 if (*src == '`') 3945 ++src; 3946 len = src - var; 3947 if (len > (size_t)dstlen) 3948 len = dstlen; 3949 vim_strncpy(dst, var, len); 3950 dst += len; 3951 dstlen -= (int)len; 3952 continue; 3953 } 3954 #endif 3955 copy_char = TRUE; 3956 if ((*src == '$' 3957 #ifdef VMS 3958 && at_start 3959 #endif 3960 ) 3961 #if defined(MSWIN) 3962 || *src == '%' 3963 #endif 3964 || (*src == '~' && at_start)) 3965 { 3966 mustfree = FALSE; 3967 3968 /* 3969 * The variable name is copied into dst temporarily, because it may 3970 * be a string in read-only memory and a NUL needs to be appended. 3971 */ 3972 if (*src != '~') /* environment var */ 3973 { 3974 tail = src + 1; 3975 var = dst; 3976 c = dstlen - 1; 3977 3978 #ifdef UNIX 3979 /* Unix has ${var-name} type environment vars */ 3980 if (*tail == '{' && !vim_isIDc('{')) 3981 { 3982 tail++; /* ignore '{' */ 3983 while (c-- > 0 && *tail && *tail != '}') 3984 *var++ = *tail++; 3985 } 3986 else 3987 #endif 3988 { 3989 while (c-- > 0 && *tail != NUL && ((vim_isIDc(*tail)) 3990 #if defined(MSWIN) 3991 || (*src == '%' && *tail != '%') 3992 #endif 3993 )) 3994 { 3995 *var++ = *tail++; 3996 } 3997 } 3998 3999 #if defined(MSWIN) || defined(UNIX) 4000 # ifdef UNIX 4001 if (src[1] == '{' && *tail != '}') 4002 # else 4003 if (*src == '%' && *tail != '%') 4004 # endif 4005 var = NULL; 4006 else 4007 { 4008 # ifdef UNIX 4009 if (src[1] == '{') 4010 # else 4011 if (*src == '%') 4012 #endif 4013 ++tail; 4014 #endif 4015 *var = NUL; 4016 var = vim_getenv(dst, &mustfree); 4017 #if defined(MSWIN) || defined(UNIX) 4018 } 4019 #endif 4020 } 4021 /* home directory */ 4022 else if ( src[1] == NUL 4023 || vim_ispathsep(src[1]) 4024 || vim_strchr((char_u *)" ,\t\n", src[1]) != NULL) 4025 { 4026 var = homedir; 4027 tail = src + 1; 4028 } 4029 else /* user directory */ 4030 { 4031 #if defined(UNIX) || (defined(VMS) && defined(USER_HOME)) 4032 /* 4033 * Copy ~user to dst[], so we can put a NUL after it. 4034 */ 4035 tail = src; 4036 var = dst; 4037 c = dstlen - 1; 4038 while ( c-- > 0 4039 && *tail 4040 && vim_isfilec(*tail) 4041 && !vim_ispathsep(*tail)) 4042 *var++ = *tail++; 4043 *var = NUL; 4044 # ifdef UNIX 4045 /* 4046 * If the system supports getpwnam(), use it. 4047 * Otherwise, or if getpwnam() fails, the shell is used to 4048 * expand ~user. This is slower and may fail if the shell 4049 * does not support ~user (old versions of /bin/sh). 4050 */ 4051 # if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H) 4052 { 4053 /* Note: memory allocated by getpwnam() is never freed. 4054 * Calling endpwent() apparently doesn't help. */ 4055 struct passwd *pw = (*dst == NUL) 4056 ? NULL : getpwnam((char *)dst + 1); 4057 4058 var = (pw == NULL) ? NULL : (char_u *)pw->pw_dir; 4059 } 4060 if (var == NULL) 4061 # endif 4062 { 4063 expand_T xpc; 4064 4065 ExpandInit(&xpc); 4066 xpc.xp_context = EXPAND_FILES; 4067 var = ExpandOne(&xpc, dst, NULL, 4068 WILD_ADD_SLASH|WILD_SILENT, WILD_EXPAND_FREE); 4069 mustfree = TRUE; 4070 } 4071 4072 # else /* !UNIX, thus VMS */ 4073 /* 4074 * USER_HOME is a comma-separated list of 4075 * directories to search for the user account in. 4076 */ 4077 { 4078 char_u test[MAXPATHL], paths[MAXPATHL]; 4079 char_u *path, *next_path, *ptr; 4080 stat_T st; 4081 4082 STRCPY(paths, USER_HOME); 4083 next_path = paths; 4084 while (*next_path) 4085 { 4086 for (path = next_path; *next_path && *next_path != ','; 4087 next_path++); 4088 if (*next_path) 4089 *next_path++ = NUL; 4090 STRCPY(test, path); 4091 STRCAT(test, "/"); 4092 STRCAT(test, dst + 1); 4093 if (mch_stat(test, &st) == 0) 4094 { 4095 var = alloc(STRLEN(test) + 1); 4096 STRCPY(var, test); 4097 mustfree = TRUE; 4098 break; 4099 } 4100 } 4101 } 4102 # endif /* UNIX */ 4103 #else 4104 /* cannot expand user's home directory, so don't try */ 4105 var = NULL; 4106 tail = (char_u *)""; /* for gcc */ 4107 #endif /* UNIX || VMS */ 4108 } 4109 4110 #ifdef BACKSLASH_IN_FILENAME 4111 /* If 'shellslash' is set change backslashes to forward slashes. 4112 * Can't use slash_adjust(), p_ssl may be set temporarily. */ 4113 if (p_ssl && var != NULL && vim_strchr(var, '\\') != NULL) 4114 { 4115 char_u *p = vim_strsave(var); 4116 4117 if (p != NULL) 4118 { 4119 if (mustfree) 4120 vim_free(var); 4121 var = p; 4122 mustfree = TRUE; 4123 forward_slash(var); 4124 } 4125 } 4126 #endif 4127 4128 /* If "var" contains white space, escape it with a backslash. 4129 * Required for ":e ~/tt" when $HOME includes a space. */ 4130 if (esc && var != NULL && vim_strpbrk(var, (char_u *)" \t") != NULL) 4131 { 4132 char_u *p = vim_strsave_escaped(var, (char_u *)" \t"); 4133 4134 if (p != NULL) 4135 { 4136 if (mustfree) 4137 vim_free(var); 4138 var = p; 4139 mustfree = TRUE; 4140 } 4141 } 4142 4143 if (var != NULL && *var != NUL 4144 && (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen)) 4145 { 4146 STRCPY(dst, var); 4147 dstlen -= (int)STRLEN(var); 4148 c = (int)STRLEN(var); 4149 /* if var[] ends in a path separator and tail[] starts 4150 * with it, skip a character */ 4151 if (*var != NUL && after_pathsep(dst, dst + c) 4152 #if defined(BACKSLASH_IN_FILENAME) || defined(AMIGA) 4153 && dst[-1] != ':' 4154 #endif 4155 && vim_ispathsep(*tail)) 4156 ++tail; 4157 dst += c; 4158 src = tail; 4159 copy_char = FALSE; 4160 } 4161 if (mustfree) 4162 vim_free(var); 4163 } 4164 4165 if (copy_char) /* copy at least one char */ 4166 { 4167 /* 4168 * Recognize the start of a new name, for '~'. 4169 * Don't do this when "one" is TRUE, to avoid expanding "~" in 4170 * ":edit foo ~ foo". 4171 */ 4172 at_start = FALSE; 4173 if (src[0] == '\\' && src[1] != NUL) 4174 { 4175 *dst++ = *src++; 4176 --dstlen; 4177 } 4178 else if ((src[0] == ' ' || src[0] == ',') && !one) 4179 at_start = TRUE; 4180 *dst++ = *src++; 4181 --dstlen; 4182 4183 if (startstr != NULL && src - startstr_len >= srcp 4184 && STRNCMP(src - startstr_len, startstr, startstr_len) == 0) 4185 at_start = TRUE; 4186 } 4187 } 4188 *dst = NUL; 4189 } 4190 4191 /* 4192 * Vim's version of getenv(). 4193 * Special handling of $HOME, $VIM and $VIMRUNTIME. 4194 * Also does ACP to 'enc' conversion for Win32. 4195 * "mustfree" is set to TRUE when returned is allocated, it must be 4196 * initialized to FALSE by the caller. 4197 */ 4198 char_u * 4199 vim_getenv(char_u *name, int *mustfree) 4200 { 4201 char_u *p; 4202 char_u *pend; 4203 int vimruntime; 4204 4205 #if defined(MSWIN) 4206 /* use "C:/" when $HOME is not set */ 4207 if (STRCMP(name, "HOME") == 0) 4208 return homedir; 4209 #endif 4210 4211 p = mch_getenv(name); 4212 if (p != NULL && *p == NUL) /* empty is the same as not set */ 4213 p = NULL; 4214 4215 if (p != NULL) 4216 { 4217 #if defined(FEAT_MBYTE) && defined(WIN3264) 4218 if (enc_utf8) 4219 { 4220 int len; 4221 char_u *pp = NULL; 4222 4223 /* Convert from active codepage to UTF-8. Other conversions are 4224 * not done, because they would fail for non-ASCII characters. */ 4225 acp_to_enc(p, (int)STRLEN(p), &pp, &len); 4226 if (pp != NULL) 4227 { 4228 p = pp; 4229 *mustfree = TRUE; 4230 } 4231 } 4232 #endif 4233 return p; 4234 } 4235 4236 vimruntime = (STRCMP(name, "VIMRUNTIME") == 0); 4237 if (!vimruntime && STRCMP(name, "VIM") != 0) 4238 return NULL; 4239 4240 /* 4241 * When expanding $VIMRUNTIME fails, try using $VIM/vim<version> or $VIM. 4242 * Don't do this when default_vimruntime_dir is non-empty. 4243 */ 4244 if (vimruntime 4245 #ifdef HAVE_PATHDEF 4246 && *default_vimruntime_dir == NUL 4247 #endif 4248 ) 4249 { 4250 p = mch_getenv((char_u *)"VIM"); 4251 if (p != NULL && *p == NUL) /* empty is the same as not set */ 4252 p = NULL; 4253 if (p != NULL) 4254 { 4255 p = vim_version_dir(p); 4256 if (p != NULL) 4257 *mustfree = TRUE; 4258 else 4259 p = mch_getenv((char_u *)"VIM"); 4260 4261 #if defined(FEAT_MBYTE) && defined(WIN3264) 4262 if (enc_utf8) 4263 { 4264 int len; 4265 char_u *pp = NULL; 4266 4267 /* Convert from active codepage to UTF-8. Other conversions 4268 * are not done, because they would fail for non-ASCII 4269 * characters. */ 4270 acp_to_enc(p, (int)STRLEN(p), &pp, &len); 4271 if (pp != NULL) 4272 { 4273 if (*mustfree) 4274 vim_free(p); 4275 p = pp; 4276 *mustfree = TRUE; 4277 } 4278 } 4279 #endif 4280 } 4281 } 4282 4283 /* 4284 * When expanding $VIM or $VIMRUNTIME fails, try using: 4285 * - the directory name from 'helpfile' (unless it contains '$') 4286 * - the executable name from argv[0] 4287 */ 4288 if (p == NULL) 4289 { 4290 if (p_hf != NULL && vim_strchr(p_hf, '$') == NULL) 4291 p = p_hf; 4292 #ifdef USE_EXE_NAME 4293 /* 4294 * Use the name of the executable, obtained from argv[0]. 4295 */ 4296 else 4297 p = exe_name; 4298 #endif 4299 if (p != NULL) 4300 { 4301 /* remove the file name */ 4302 pend = gettail(p); 4303 4304 /* remove "doc/" from 'helpfile', if present */ 4305 if (p == p_hf) 4306 pend = remove_tail(p, pend, (char_u *)"doc"); 4307 4308 #ifdef USE_EXE_NAME 4309 # ifdef MACOS_X 4310 /* remove "MacOS" from exe_name and add "Resources/vim" */ 4311 if (p == exe_name) 4312 { 4313 char_u *pend1; 4314 char_u *pnew; 4315 4316 pend1 = remove_tail(p, pend, (char_u *)"MacOS"); 4317 if (pend1 != pend) 4318 { 4319 pnew = alloc((unsigned)(pend1 - p) + 15); 4320 if (pnew != NULL) 4321 { 4322 STRNCPY(pnew, p, (pend1 - p)); 4323 STRCPY(pnew + (pend1 - p), "Resources/vim"); 4324 p = pnew; 4325 pend = p + STRLEN(p); 4326 } 4327 } 4328 } 4329 # endif 4330 /* remove "src/" from exe_name, if present */ 4331 if (p == exe_name) 4332 pend = remove_tail(p, pend, (char_u *)"src"); 4333 #endif 4334 4335 /* for $VIM, remove "runtime/" or "vim54/", if present */ 4336 if (!vimruntime) 4337 { 4338 pend = remove_tail(p, pend, (char_u *)RUNTIME_DIRNAME); 4339 pend = remove_tail(p, pend, (char_u *)VIM_VERSION_NODOT); 4340 } 4341 4342 /* remove trailing path separator */ 4343 #ifndef MACOS_CLASSIC 4344 /* With MacOS path (with colons) the final colon is required */ 4345 /* to avoid confusion between absolute and relative path */ 4346 if (pend > p && after_pathsep(p, pend)) 4347 --pend; 4348 #endif 4349 4350 #ifdef MACOS_X 4351 if (p == exe_name || p == p_hf) 4352 #endif 4353 /* check that the result is a directory name */ 4354 p = vim_strnsave(p, (int)(pend - p)); 4355 4356 if (p != NULL && !mch_isdir(p)) 4357 { 4358 vim_free(p); 4359 p = NULL; 4360 } 4361 else 4362 { 4363 #ifdef USE_EXE_NAME 4364 /* may add "/vim54" or "/runtime" if it exists */ 4365 if (vimruntime && (pend = vim_version_dir(p)) != NULL) 4366 { 4367 vim_free(p); 4368 p = pend; 4369 } 4370 #endif 4371 *mustfree = TRUE; 4372 } 4373 } 4374 } 4375 4376 #ifdef HAVE_PATHDEF 4377 /* When there is a pathdef.c file we can use default_vim_dir and 4378 * default_vimruntime_dir */ 4379 if (p == NULL) 4380 { 4381 /* Only use default_vimruntime_dir when it is not empty */ 4382 if (vimruntime && *default_vimruntime_dir != NUL) 4383 { 4384 p = default_vimruntime_dir; 4385 *mustfree = FALSE; 4386 } 4387 else if (*default_vim_dir != NUL) 4388 { 4389 if (vimruntime && (p = vim_version_dir(default_vim_dir)) != NULL) 4390 *mustfree = TRUE; 4391 else 4392 { 4393 p = default_vim_dir; 4394 *mustfree = FALSE; 4395 } 4396 } 4397 } 4398 #endif 4399 4400 /* 4401 * Set the environment variable, so that the new value can be found fast 4402 * next time, and others can also use it (e.g. Perl). 4403 */ 4404 if (p != NULL) 4405 { 4406 if (vimruntime) 4407 { 4408 vim_setenv((char_u *)"VIMRUNTIME", p); 4409 didset_vimruntime = TRUE; 4410 } 4411 else 4412 { 4413 vim_setenv((char_u *)"VIM", p); 4414 didset_vim = TRUE; 4415 } 4416 } 4417 return p; 4418 } 4419 4420 /* 4421 * Check if the directory "vimdir/<version>" or "vimdir/runtime" exists. 4422 * Return NULL if not, return its name in allocated memory otherwise. 4423 */ 4424 static char_u * 4425 vim_version_dir(char_u *vimdir) 4426 { 4427 char_u *p; 4428 4429 if (vimdir == NULL || *vimdir == NUL) 4430 return NULL; 4431 p = concat_fnames(vimdir, (char_u *)VIM_VERSION_NODOT, TRUE); 4432 if (p != NULL && mch_isdir(p)) 4433 return p; 4434 vim_free(p); 4435 p = concat_fnames(vimdir, (char_u *)RUNTIME_DIRNAME, TRUE); 4436 if (p != NULL && mch_isdir(p)) 4437 return p; 4438 vim_free(p); 4439 return NULL; 4440 } 4441 4442 /* 4443 * If the string between "p" and "pend" ends in "name/", return "pend" minus 4444 * the length of "name/". Otherwise return "pend". 4445 */ 4446 static char_u * 4447 remove_tail(char_u *p, char_u *pend, char_u *name) 4448 { 4449 int len = (int)STRLEN(name) + 1; 4450 char_u *newend = pend - len; 4451 4452 if (newend >= p 4453 && fnamencmp(newend, name, len - 1) == 0 4454 && (newend == p || after_pathsep(p, newend))) 4455 return newend; 4456 return pend; 4457 } 4458 4459 /* 4460 * Our portable version of setenv. 4461 */ 4462 void 4463 vim_setenv(char_u *name, char_u *val) 4464 { 4465 #ifdef HAVE_SETENV 4466 mch_setenv((char *)name, (char *)val, 1); 4467 #else 4468 char_u *envbuf; 4469 4470 /* 4471 * Putenv does not copy the string, it has to remain 4472 * valid. The allocated memory will never be freed. 4473 */ 4474 envbuf = alloc((unsigned)(STRLEN(name) + STRLEN(val) + 2)); 4475 if (envbuf != NULL) 4476 { 4477 sprintf((char *)envbuf, "%s=%s", name, val); 4478 putenv((char *)envbuf); 4479 } 4480 #endif 4481 #ifdef FEAT_GETTEXT 4482 /* 4483 * When setting $VIMRUNTIME adjust the directory to find message 4484 * translations to $VIMRUNTIME/lang. 4485 */ 4486 if (*val != NUL && STRICMP(name, "VIMRUNTIME") == 0) 4487 { 4488 char_u *buf = concat_str(val, (char_u *)"/lang"); 4489 4490 if (buf != NULL) 4491 { 4492 bindtextdomain(VIMPACKAGE, (char *)buf); 4493 vim_free(buf); 4494 } 4495 } 4496 #endif 4497 } 4498 4499 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 4500 /* 4501 * Function given to ExpandGeneric() to obtain an environment variable name. 4502 */ 4503 char_u * 4504 get_env_name( 4505 expand_T *xp UNUSED, 4506 int idx) 4507 { 4508 # if defined(AMIGA) || defined(__MRC__) || defined(__SC__) 4509 /* 4510 * No environ[] on the Amiga and on the Mac (using MPW). 4511 */ 4512 return NULL; 4513 # else 4514 # ifndef __WIN32__ 4515 /* Borland C++ 5.2 has this in a header file. */ 4516 extern char **environ; 4517 # endif 4518 # define ENVNAMELEN 100 4519 static char_u name[ENVNAMELEN]; 4520 char_u *str; 4521 int n; 4522 4523 str = (char_u *)environ[idx]; 4524 if (str == NULL) 4525 return NULL; 4526 4527 for (n = 0; n < ENVNAMELEN - 1; ++n) 4528 { 4529 if (str[n] == '=' || str[n] == NUL) 4530 break; 4531 name[n] = str[n]; 4532 } 4533 name[n] = NUL; 4534 return name; 4535 # endif 4536 } 4537 4538 /* 4539 * Find all user names for user completion. 4540 * Done only once and then cached. 4541 */ 4542 static void 4543 init_users(void) 4544 { 4545 static int lazy_init_done = FALSE; 4546 4547 if (lazy_init_done) 4548 return; 4549 4550 lazy_init_done = TRUE; 4551 ga_init2(&ga_users, sizeof(char_u *), 20); 4552 4553 # if defined(HAVE_GETPWENT) && defined(HAVE_PWD_H) 4554 { 4555 char_u* user; 4556 struct passwd* pw; 4557 4558 setpwent(); 4559 while ((pw = getpwent()) != NULL) 4560 /* pw->pw_name shouldn't be NULL but just in case... */ 4561 if (pw->pw_name != NULL) 4562 { 4563 if (ga_grow(&ga_users, 1) == FAIL) 4564 break; 4565 user = vim_strsave((char_u*)pw->pw_name); 4566 if (user == NULL) 4567 break; 4568 ((char_u **)(ga_users.ga_data))[ga_users.ga_len++] = user; 4569 } 4570 endpwent(); 4571 } 4572 # endif 4573 } 4574 4575 /* 4576 * Function given to ExpandGeneric() to obtain an user names. 4577 */ 4578 char_u* 4579 get_users(expand_T *xp UNUSED, int idx) 4580 { 4581 init_users(); 4582 if (idx < ga_users.ga_len) 4583 return ((char_u **)ga_users.ga_data)[idx]; 4584 return NULL; 4585 } 4586 4587 /* 4588 * Check whether name matches a user name. Return: 4589 * 0 if name does not match any user name. 4590 * 1 if name partially matches the beginning of a user name. 4591 * 2 is name fully matches a user name. 4592 */ 4593 int match_user(char_u* name) 4594 { 4595 int i; 4596 int n = (int)STRLEN(name); 4597 int result = 0; 4598 4599 init_users(); 4600 for (i = 0; i < ga_users.ga_len; i++) 4601 { 4602 if (STRCMP(((char_u **)ga_users.ga_data)[i], name) == 0) 4603 return 2; /* full match */ 4604 if (STRNCMP(((char_u **)ga_users.ga_data)[i], name, n) == 0) 4605 result = 1; /* partial match */ 4606 } 4607 return result; 4608 } 4609 #endif 4610 4611 /* 4612 * Replace home directory by "~" in each space or comma separated file name in 4613 * 'src'. 4614 * If anything fails (except when out of space) dst equals src. 4615 */ 4616 void 4617 home_replace( 4618 buf_T *buf, /* when not NULL, check for help files */ 4619 char_u *src, /* input file name */ 4620 char_u *dst, /* where to put the result */ 4621 int dstlen, /* maximum length of the result */ 4622 int one) /* if TRUE, only replace one file name, include 4623 spaces and commas in the file name. */ 4624 { 4625 size_t dirlen = 0, envlen = 0; 4626 size_t len; 4627 char_u *homedir_env, *homedir_env_orig; 4628 char_u *p; 4629 4630 if (src == NULL) 4631 { 4632 *dst = NUL; 4633 return; 4634 } 4635 4636 /* 4637 * If the file is a help file, remove the path completely. 4638 */ 4639 if (buf != NULL && buf->b_help) 4640 { 4641 STRCPY(dst, gettail(src)); 4642 return; 4643 } 4644 4645 /* 4646 * We check both the value of the $HOME environment variable and the 4647 * "real" home directory. 4648 */ 4649 if (homedir != NULL) 4650 dirlen = STRLEN(homedir); 4651 4652 #ifdef VMS 4653 homedir_env_orig = homedir_env = mch_getenv((char_u *)"SYS$LOGIN"); 4654 #else 4655 homedir_env_orig = homedir_env = mch_getenv((char_u *)"HOME"); 4656 #endif 4657 /* Empty is the same as not set. */ 4658 if (homedir_env != NULL && *homedir_env == NUL) 4659 homedir_env = NULL; 4660 4661 #if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) 4662 if (homedir_env != NULL && vim_strchr(homedir_env, '~') != NULL) 4663 { 4664 int usedlen = 0; 4665 int flen; 4666 char_u *fbuf = NULL; 4667 4668 flen = (int)STRLEN(homedir_env); 4669 (void)modify_fname((char_u *)":p", &usedlen, 4670 &homedir_env, &fbuf, &flen); 4671 flen = (int)STRLEN(homedir_env); 4672 if (flen > 0 && vim_ispathsep(homedir_env[flen - 1])) 4673 /* Remove the trailing / that is added to a directory. */ 4674 homedir_env[flen - 1] = NUL; 4675 } 4676 #endif 4677 4678 if (homedir_env != NULL) 4679 envlen = STRLEN(homedir_env); 4680 4681 if (!one) 4682 src = skipwhite(src); 4683 while (*src && dstlen > 0) 4684 { 4685 /* 4686 * Here we are at the beginning of a file name. 4687 * First, check to see if the beginning of the file name matches 4688 * $HOME or the "real" home directory. Check that there is a '/' 4689 * after the match (so that if e.g. the file is "/home/pieter/bla", 4690 * and the home directory is "/home/piet", the file does not end up 4691 * as "~er/bla" (which would seem to indicate the file "bla" in user 4692 * er's home directory)). 4693 */ 4694 p = homedir; 4695 len = dirlen; 4696 for (;;) 4697 { 4698 if ( len 4699 && fnamencmp(src, p, len) == 0 4700 && (vim_ispathsep(src[len]) 4701 || (!one && (src[len] == ',' || src[len] == ' ')) 4702 || src[len] == NUL)) 4703 { 4704 src += len; 4705 if (--dstlen > 0) 4706 *dst++ = '~'; 4707 4708 /* 4709 * If it's just the home directory, add "/". 4710 */ 4711 if (!vim_ispathsep(src[0]) && --dstlen > 0) 4712 *dst++ = '/'; 4713 break; 4714 } 4715 if (p == homedir_env) 4716 break; 4717 p = homedir_env; 4718 len = envlen; 4719 } 4720 4721 /* if (!one) skip to separator: space or comma */ 4722 while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0) 4723 *dst++ = *src++; 4724 /* skip separator */ 4725 while ((*src == ' ' || *src == ',') && --dstlen > 0) 4726 *dst++ = *src++; 4727 } 4728 /* if (dstlen == 0) out of space, what to do??? */ 4729 4730 *dst = NUL; 4731 4732 if (homedir_env != homedir_env_orig) 4733 vim_free(homedir_env); 4734 } 4735 4736 /* 4737 * Like home_replace, store the replaced string in allocated memory. 4738 * When something fails, NULL is returned. 4739 */ 4740 char_u * 4741 home_replace_save( 4742 buf_T *buf, /* when not NULL, check for help files */ 4743 char_u *src) /* input file name */ 4744 { 4745 char_u *dst; 4746 unsigned len; 4747 4748 len = 3; /* space for "~/" and trailing NUL */ 4749 if (src != NULL) /* just in case */ 4750 len += (unsigned)STRLEN(src); 4751 dst = alloc(len); 4752 if (dst != NULL) 4753 home_replace(buf, src, dst, len, TRUE); 4754 return dst; 4755 } 4756 4757 /* 4758 * Compare two file names and return: 4759 * FPC_SAME if they both exist and are the same file. 4760 * FPC_SAMEX if they both don't exist and have the same file name. 4761 * FPC_DIFF if they both exist and are different files. 4762 * FPC_NOTX if they both don't exist. 4763 * FPC_DIFFX if one of them doesn't exist. 4764 * For the first name environment variables are expanded 4765 */ 4766 int 4767 fullpathcmp( 4768 char_u *s1, 4769 char_u *s2, 4770 int checkname) /* when both don't exist, check file names */ 4771 { 4772 #ifdef UNIX 4773 char_u exp1[MAXPATHL]; 4774 char_u full1[MAXPATHL]; 4775 char_u full2[MAXPATHL]; 4776 stat_T st1, st2; 4777 int r1, r2; 4778 4779 expand_env(s1, exp1, MAXPATHL); 4780 r1 = mch_stat((char *)exp1, &st1); 4781 r2 = mch_stat((char *)s2, &st2); 4782 if (r1 != 0 && r2 != 0) 4783 { 4784 /* if mch_stat() doesn't work, may compare the names */ 4785 if (checkname) 4786 { 4787 if (fnamecmp(exp1, s2) == 0) 4788 return FPC_SAMEX; 4789 r1 = vim_FullName(exp1, full1, MAXPATHL, FALSE); 4790 r2 = vim_FullName(s2, full2, MAXPATHL, FALSE); 4791 if (r1 == OK && r2 == OK && fnamecmp(full1, full2) == 0) 4792 return FPC_SAMEX; 4793 } 4794 return FPC_NOTX; 4795 } 4796 if (r1 != 0 || r2 != 0) 4797 return FPC_DIFFX; 4798 if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) 4799 return FPC_SAME; 4800 return FPC_DIFF; 4801 #else 4802 char_u *exp1; /* expanded s1 */ 4803 char_u *full1; /* full path of s1 */ 4804 char_u *full2; /* full path of s2 */ 4805 int retval = FPC_DIFF; 4806 int r1, r2; 4807 4808 /* allocate one buffer to store three paths (alloc()/free() is slow!) */ 4809 if ((exp1 = alloc(MAXPATHL * 3)) != NULL) 4810 { 4811 full1 = exp1 + MAXPATHL; 4812 full2 = full1 + MAXPATHL; 4813 4814 expand_env(s1, exp1, MAXPATHL); 4815 r1 = vim_FullName(exp1, full1, MAXPATHL, FALSE); 4816 r2 = vim_FullName(s2, full2, MAXPATHL, FALSE); 4817 4818 /* If vim_FullName() fails, the file probably doesn't exist. */ 4819 if (r1 != OK && r2 != OK) 4820 { 4821 if (checkname && fnamecmp(exp1, s2) == 0) 4822 retval = FPC_SAMEX; 4823 else 4824 retval = FPC_NOTX; 4825 } 4826 else if (r1 != OK || r2 != OK) 4827 retval = FPC_DIFFX; 4828 else if (fnamecmp(full1, full2)) 4829 retval = FPC_DIFF; 4830 else 4831 retval = FPC_SAME; 4832 vim_free(exp1); 4833 } 4834 return retval; 4835 #endif 4836 } 4837 4838 /* 4839 * Get the tail of a path: the file name. 4840 * When the path ends in a path separator the tail is the NUL after it. 4841 * Fail safe: never returns NULL. 4842 */ 4843 char_u * 4844 gettail(char_u *fname) 4845 { 4846 char_u *p1, *p2; 4847 4848 if (fname == NULL) 4849 return (char_u *)""; 4850 for (p1 = p2 = get_past_head(fname); *p2; ) /* find last part of path */ 4851 { 4852 if (vim_ispathsep_nocolon(*p2)) 4853 p1 = p2 + 1; 4854 MB_PTR_ADV(p2); 4855 } 4856 return p1; 4857 } 4858 4859 #if defined(FEAT_SEARCHPATH) 4860 static char_u *gettail_dir(char_u *fname); 4861 4862 /* 4863 * Return the end of the directory name, on the first path 4864 * separator: 4865 * "/path/file", "/path/dir/", "/path//dir", "/file" 4866 * ^ ^ ^ ^ 4867 */ 4868 static char_u * 4869 gettail_dir(char_u *fname) 4870 { 4871 char_u *dir_end = fname; 4872 char_u *next_dir_end = fname; 4873 int look_for_sep = TRUE; 4874 char_u *p; 4875 4876 for (p = fname; *p != NUL; ) 4877 { 4878 if (vim_ispathsep(*p)) 4879 { 4880 if (look_for_sep) 4881 { 4882 next_dir_end = p; 4883 look_for_sep = FALSE; 4884 } 4885 } 4886 else 4887 { 4888 if (!look_for_sep) 4889 dir_end = next_dir_end; 4890 look_for_sep = TRUE; 4891 } 4892 MB_PTR_ADV(p); 4893 } 4894 return dir_end; 4895 } 4896 #endif 4897 4898 /* 4899 * Get pointer to tail of "fname", including path separators. Putting a NUL 4900 * here leaves the directory name. Takes care of "c:/" and "//". 4901 * Always returns a valid pointer. 4902 */ 4903 char_u * 4904 gettail_sep(char_u *fname) 4905 { 4906 char_u *p; 4907 char_u *t; 4908 4909 p = get_past_head(fname); /* don't remove the '/' from "c:/file" */ 4910 t = gettail(fname); 4911 while (t > p && after_pathsep(fname, t)) 4912 --t; 4913 #ifdef VMS 4914 /* path separator is part of the path */ 4915 ++t; 4916 #endif 4917 return t; 4918 } 4919 4920 /* 4921 * get the next path component (just after the next path separator). 4922 */ 4923 char_u * 4924 getnextcomp(char_u *fname) 4925 { 4926 while (*fname && !vim_ispathsep(*fname)) 4927 MB_PTR_ADV(fname); 4928 if (*fname) 4929 ++fname; 4930 return fname; 4931 } 4932 4933 /* 4934 * Get a pointer to one character past the head of a path name. 4935 * Unix: after "/"; DOS: after "c:\"; Amiga: after "disk:/"; Mac: no head. 4936 * If there is no head, path is returned. 4937 */ 4938 char_u * 4939 get_past_head(char_u *path) 4940 { 4941 char_u *retval; 4942 4943 #if defined(MSWIN) 4944 /* may skip "c:" */ 4945 if (isalpha(path[0]) && path[1] == ':') 4946 retval = path + 2; 4947 else 4948 retval = path; 4949 #else 4950 # if defined(AMIGA) 4951 /* may skip "label:" */ 4952 retval = vim_strchr(path, ':'); 4953 if (retval == NULL) 4954 retval = path; 4955 # else /* Unix */ 4956 retval = path; 4957 # endif 4958 #endif 4959 4960 while (vim_ispathsep(*retval)) 4961 ++retval; 4962 4963 return retval; 4964 } 4965 4966 /* 4967 * Return TRUE if 'c' is a path separator. 4968 * Note that for MS-Windows this includes the colon. 4969 */ 4970 int 4971 vim_ispathsep(int c) 4972 { 4973 #ifdef UNIX 4974 return (c == '/'); /* UNIX has ':' inside file names */ 4975 #else 4976 # ifdef BACKSLASH_IN_FILENAME 4977 return (c == ':' || c == '/' || c == '\\'); 4978 # else 4979 # ifdef VMS 4980 /* server"user passwd"::device:[full.path.name]fname.extension;version" */ 4981 return (c == ':' || c == '[' || c == ']' || c == '/' 4982 || c == '<' || c == '>' || c == '"' ); 4983 # else 4984 return (c == ':' || c == '/'); 4985 # endif /* VMS */ 4986 # endif 4987 #endif 4988 } 4989 4990 /* 4991 * Like vim_ispathsep(c), but exclude the colon for MS-Windows. 4992 */ 4993 int 4994 vim_ispathsep_nocolon(int c) 4995 { 4996 return vim_ispathsep(c) 4997 #ifdef BACKSLASH_IN_FILENAME 4998 && c != ':' 4999 #endif 5000 ; 5001 } 5002 5003 #if defined(FEAT_SEARCHPATH) || defined(PROTO) 5004 /* 5005 * return TRUE if 'c' is a path list separator. 5006 */ 5007 int 5008 vim_ispathlistsep(int c) 5009 { 5010 #ifdef UNIX 5011 return (c == ':'); 5012 #else 5013 return (c == ';'); /* might not be right for every system... */ 5014 #endif 5015 } 5016 #endif 5017 5018 #if defined(FEAT_GUI_TABLINE) || defined(FEAT_WINDOWS) \ 5019 || defined(FEAT_EVAL) || defined(PROTO) 5020 /* 5021 * Shorten the path of a file from "~/foo/../.bar/fname" to "~/f/../.b/fname" 5022 * It's done in-place. 5023 */ 5024 void 5025 shorten_dir(char_u *str) 5026 { 5027 char_u *tail, *s, *d; 5028 int skip = FALSE; 5029 5030 tail = gettail(str); 5031 d = str; 5032 for (s = str; ; ++s) 5033 { 5034 if (s >= tail) /* copy the whole tail */ 5035 { 5036 *d++ = *s; 5037 if (*s == NUL) 5038 break; 5039 } 5040 else if (vim_ispathsep(*s)) /* copy '/' and next char */ 5041 { 5042 *d++ = *s; 5043 skip = FALSE; 5044 } 5045 else if (!skip) 5046 { 5047 *d++ = *s; /* copy next char */ 5048 if (*s != '~' && *s != '.') /* and leading "~" and "." */ 5049 skip = TRUE; 5050 # ifdef FEAT_MBYTE 5051 if (has_mbyte) 5052 { 5053 int l = mb_ptr2len(s); 5054 5055 while (--l > 0) 5056 *d++ = *++s; 5057 } 5058 # endif 5059 } 5060 } 5061 } 5062 #endif 5063 5064 /* 5065 * Return TRUE if the directory of "fname" exists, FALSE otherwise. 5066 * Also returns TRUE if there is no directory name. 5067 * "fname" must be writable!. 5068 */ 5069 int 5070 dir_of_file_exists(char_u *fname) 5071 { 5072 char_u *p; 5073 int c; 5074 int retval; 5075 5076 p = gettail_sep(fname); 5077 if (p == fname) 5078 return TRUE; 5079 c = *p; 5080 *p = NUL; 5081 retval = mch_isdir(fname); 5082 *p = c; 5083 return retval; 5084 } 5085 5086 /* 5087 * Versions of fnamecmp() and fnamencmp() that handle '/' and '\' equally 5088 * and deal with 'fileignorecase'. 5089 */ 5090 int 5091 vim_fnamecmp(char_u *x, char_u *y) 5092 { 5093 #ifdef BACKSLASH_IN_FILENAME 5094 return vim_fnamencmp(x, y, MAXPATHL); 5095 #else 5096 if (p_fic) 5097 return MB_STRICMP(x, y); 5098 return STRCMP(x, y); 5099 #endif 5100 } 5101 5102 int 5103 vim_fnamencmp(char_u *x, char_u *y, size_t len) 5104 { 5105 #ifdef BACKSLASH_IN_FILENAME 5106 char_u *px = x; 5107 char_u *py = y; 5108 int cx = NUL; 5109 int cy = NUL; 5110 5111 while (len > 0) 5112 { 5113 cx = PTR2CHAR(px); 5114 cy = PTR2CHAR(py); 5115 if (cx == NUL || cy == NUL 5116 || ((p_fic ? MB_TOLOWER(cx) != MB_TOLOWER(cy) : cx != cy) 5117 && !(cx == '/' && cy == '\\') 5118 && !(cx == '\\' && cy == '/'))) 5119 break; 5120 len -= MB_PTR2LEN(px); 5121 px += MB_PTR2LEN(px); 5122 py += MB_PTR2LEN(py); 5123 } 5124 if (len == 0) 5125 return 0; 5126 return (cx - cy); 5127 #else 5128 if (p_fic) 5129 return MB_STRNICMP(x, y, len); 5130 return STRNCMP(x, y, len); 5131 #endif 5132 } 5133 5134 /* 5135 * Concatenate file names fname1 and fname2 into allocated memory. 5136 * Only add a '/' or '\\' when 'sep' is TRUE and it is necessary. 5137 */ 5138 char_u * 5139 concat_fnames(char_u *fname1, char_u *fname2, int sep) 5140 { 5141 char_u *dest; 5142 5143 dest = alloc((unsigned)(STRLEN(fname1) + STRLEN(fname2) + 3)); 5144 if (dest != NULL) 5145 { 5146 STRCPY(dest, fname1); 5147 if (sep) 5148 add_pathsep(dest); 5149 STRCAT(dest, fname2); 5150 } 5151 return dest; 5152 } 5153 5154 /* 5155 * Concatenate two strings and return the result in allocated memory. 5156 * Returns NULL when out of memory. 5157 */ 5158 char_u * 5159 concat_str(char_u *str1, char_u *str2) 5160 { 5161 char_u *dest; 5162 size_t l = STRLEN(str1); 5163 5164 dest = alloc((unsigned)(l + STRLEN(str2) + 1L)); 5165 if (dest != NULL) 5166 { 5167 STRCPY(dest, str1); 5168 STRCPY(dest + l, str2); 5169 } 5170 return dest; 5171 } 5172 5173 /* 5174 * Add a path separator to a file name, unless it already ends in a path 5175 * separator. 5176 */ 5177 void 5178 add_pathsep(char_u *p) 5179 { 5180 if (*p != NUL && !after_pathsep(p, p + STRLEN(p))) 5181 STRCAT(p, PATHSEPSTR); 5182 } 5183 5184 /* 5185 * FullName_save - Make an allocated copy of a full file name. 5186 * Returns NULL when out of memory. 5187 */ 5188 char_u * 5189 FullName_save( 5190 char_u *fname, 5191 int force) /* force expansion, even when it already looks 5192 * like a full path name */ 5193 { 5194 char_u *buf; 5195 char_u *new_fname = NULL; 5196 5197 if (fname == NULL) 5198 return NULL; 5199 5200 buf = alloc((unsigned)MAXPATHL); 5201 if (buf != NULL) 5202 { 5203 if (vim_FullName(fname, buf, MAXPATHL, force) != FAIL) 5204 new_fname = vim_strsave(buf); 5205 else 5206 new_fname = vim_strsave(fname); 5207 vim_free(buf); 5208 } 5209 return new_fname; 5210 } 5211 5212 #if defined(FEAT_CINDENT) || defined(FEAT_SYN_HL) 5213 5214 static char_u *skip_string(char_u *p); 5215 static pos_T *ind_find_start_comment(void); 5216 static pos_T *ind_find_start_CORS(void); 5217 static pos_T *find_start_rawstring(int ind_maxcomment); 5218 5219 /* 5220 * Find the start of a comment, not knowing if we are in a comment right now. 5221 * Search starts at w_cursor.lnum and goes backwards. 5222 * Return NULL when not inside a comment. 5223 */ 5224 static pos_T * 5225 ind_find_start_comment(void) /* XXX */ 5226 { 5227 return find_start_comment(curbuf->b_ind_maxcomment); 5228 } 5229 5230 pos_T * 5231 find_start_comment(int ind_maxcomment) /* XXX */ 5232 { 5233 pos_T *pos; 5234 char_u *line; 5235 char_u *p; 5236 int cur_maxcomment = ind_maxcomment; 5237 5238 for (;;) 5239 { 5240 pos = findmatchlimit(NULL, '*', FM_BACKWARD, cur_maxcomment); 5241 if (pos == NULL) 5242 break; 5243 5244 /* 5245 * Check if the comment start we found is inside a string. 5246 * If it is then restrict the search to below this line and try again. 5247 */ 5248 line = ml_get(pos->lnum); 5249 for (p = line; *p && (colnr_T)(p - line) < pos->col; ++p) 5250 p = skip_string(p); 5251 if ((colnr_T)(p - line) <= pos->col) 5252 break; 5253 cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1; 5254 if (cur_maxcomment <= 0) 5255 { 5256 pos = NULL; 5257 break; 5258 } 5259 } 5260 return pos; 5261 } 5262 5263 /* 5264 * Find the start of a comment or raw string, not knowing if we are in a 5265 * comment or raw string right now. 5266 * Search starts at w_cursor.lnum and goes backwards. 5267 * Return NULL when not inside a comment or raw string. 5268 * "CORS" -> Comment Or Raw String 5269 */ 5270 static pos_T * 5271 ind_find_start_CORS(void) /* XXX */ 5272 { 5273 static pos_T comment_pos_copy; 5274 pos_T *comment_pos; 5275 pos_T *rs_pos; 5276 5277 comment_pos = find_start_comment(curbuf->b_ind_maxcomment); 5278 if (comment_pos != NULL) 5279 { 5280 /* Need to make a copy of the static pos in findmatchlimit(), 5281 * calling find_start_rawstring() may change it. */ 5282 comment_pos_copy = *comment_pos; 5283 comment_pos = &comment_pos_copy; 5284 } 5285 rs_pos = find_start_rawstring(curbuf->b_ind_maxcomment); 5286 5287 /* If comment_pos is before rs_pos the raw string is inside the comment. 5288 * If rs_pos is before comment_pos the comment is inside the raw string. */ 5289 if (comment_pos == NULL || (rs_pos != NULL 5290 && LT_POS(*rs_pos, *comment_pos))) 5291 return rs_pos; 5292 return comment_pos; 5293 } 5294 5295 /* 5296 * Find the start of a raw string, not knowing if we are in one right now. 5297 * Search starts at w_cursor.lnum and goes backwards. 5298 * Return NULL when not inside a raw string. 5299 */ 5300 static pos_T * 5301 find_start_rawstring(int ind_maxcomment) /* XXX */ 5302 { 5303 pos_T *pos; 5304 char_u *line; 5305 char_u *p; 5306 int cur_maxcomment = ind_maxcomment; 5307 5308 for (;;) 5309 { 5310 pos = findmatchlimit(NULL, 'R', FM_BACKWARD, cur_maxcomment); 5311 if (pos == NULL) 5312 break; 5313 5314 /* 5315 * Check if the raw string start we found is inside a string. 5316 * If it is then restrict the search to below this line and try again. 5317 */ 5318 line = ml_get(pos->lnum); 5319 for (p = line; *p && (colnr_T)(p - line) < pos->col; ++p) 5320 p = skip_string(p); 5321 if ((colnr_T)(p - line) <= pos->col) 5322 break; 5323 cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1; 5324 if (cur_maxcomment <= 0) 5325 { 5326 pos = NULL; 5327 break; 5328 } 5329 } 5330 return pos; 5331 } 5332 5333 /* 5334 * Skip to the end of a "string" and a 'c' character. 5335 * If there is no string or character, return argument unmodified. 5336 */ 5337 static char_u * 5338 skip_string(char_u *p) 5339 { 5340 int i; 5341 5342 /* 5343 * We loop, because strings may be concatenated: "date""time". 5344 */ 5345 for ( ; ; ++p) 5346 { 5347 if (p[0] == '\'') /* 'c' or '\n' or '\000' */ 5348 { 5349 if (!p[1]) /* ' at end of line */ 5350 break; 5351 i = 2; 5352 if (p[1] == '\\') /* '\n' or '\000' */ 5353 { 5354 ++i; 5355 while (vim_isdigit(p[i - 1])) /* '\000' */ 5356 ++i; 5357 } 5358 if (p[i] == '\'') /* check for trailing ' */ 5359 { 5360 p += i; 5361 continue; 5362 } 5363 } 5364 else if (p[0] == '"') /* start of string */ 5365 { 5366 for (++p; p[0]; ++p) 5367 { 5368 if (p[0] == '\\' && p[1] != NUL) 5369 ++p; 5370 else if (p[0] == '"') /* end of string */ 5371 break; 5372 } 5373 if (p[0] == '"') 5374 continue; /* continue for another string */ 5375 } 5376 else if (p[0] == 'R' && p[1] == '"') 5377 { 5378 /* Raw string: R"[delim](...)[delim]" */ 5379 char_u *delim = p + 2; 5380 char_u *paren = vim_strchr(delim, '('); 5381 5382 if (paren != NULL) 5383 { 5384 size_t delim_len = paren - delim; 5385 5386 for (p += 3; *p; ++p) 5387 if (p[0] == ')' && STRNCMP(p + 1, delim, delim_len) == 0 5388 && p[delim_len + 1] == '"') 5389 { 5390 p += delim_len + 1; 5391 break; 5392 } 5393 if (p[0] == '"') 5394 continue; /* continue for another string */ 5395 } 5396 } 5397 break; /* no string found */ 5398 } 5399 if (!*p) 5400 --p; /* backup from NUL */ 5401 return p; 5402 } 5403 #endif /* FEAT_CINDENT || FEAT_SYN_HL */ 5404 5405 #if defined(FEAT_CINDENT) || defined(PROTO) 5406 5407 /* 5408 * Do C or expression indenting on the current line. 5409 */ 5410 void 5411 do_c_expr_indent(void) 5412 { 5413 # ifdef FEAT_EVAL 5414 if (*curbuf->b_p_inde != NUL) 5415 fixthisline(get_expr_indent); 5416 else 5417 # endif 5418 fixthisline(get_c_indent); 5419 } 5420 5421 /* Find result cache for cpp_baseclass */ 5422 typedef struct { 5423 int found; 5424 lpos_T lpos; 5425 } cpp_baseclass_cache_T; 5426 5427 /* 5428 * Functions for C-indenting. 5429 * Most of this originally comes from Eric Fischer. 5430 */ 5431 /* 5432 * Below "XXX" means that this function may unlock the current line. 5433 */ 5434 5435 static char_u *cin_skipcomment(char_u *); 5436 static int cin_nocode(char_u *); 5437 static pos_T *find_line_comment(void); 5438 static int cin_has_js_key(char_u *text); 5439 static int cin_islabel_skip(char_u **); 5440 static int cin_isdefault(char_u *); 5441 static char_u *after_label(char_u *l); 5442 static int get_indent_nolabel(linenr_T lnum); 5443 static int skip_label(linenr_T, char_u **pp); 5444 static int cin_first_id_amount(void); 5445 static int cin_get_equal_amount(linenr_T lnum); 5446 static int cin_ispreproc(char_u *); 5447 static int cin_iscomment(char_u *); 5448 static int cin_islinecomment(char_u *); 5449 static int cin_isterminated(char_u *, int, int); 5450 static int cin_isinit(void); 5451 static int cin_isfuncdecl(char_u **, linenr_T, linenr_T); 5452 static int cin_isif(char_u *); 5453 static int cin_iselse(char_u *); 5454 static int cin_isdo(char_u *); 5455 static int cin_iswhileofdo(char_u *, linenr_T); 5456 static int cin_is_if_for_while_before_offset(char_u *line, int *poffset); 5457 static int cin_iswhileofdo_end(int terminated); 5458 static int cin_isbreak(char_u *); 5459 static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached); 5460 static int get_baseclass_amount(int col); 5461 static int cin_ends_in(char_u *, char_u *, char_u *); 5462 static int cin_starts_with(char_u *s, char *word); 5463 static int cin_skip2pos(pos_T *trypos); 5464 static pos_T *find_start_brace(void); 5465 static pos_T *find_match_paren(int); 5466 static pos_T *find_match_char(int c, int ind_maxparen); 5467 static int corr_ind_maxparen(pos_T *startpos); 5468 static int find_last_paren(char_u *l, int start, int end); 5469 static int find_match(int lookfor, linenr_T ourscope); 5470 static int cin_is_cpp_namespace(char_u *); 5471 5472 /* 5473 * Skip over white space and C comments within the line. 5474 * Also skip over Perl/shell comments if desired. 5475 */ 5476 static char_u * 5477 cin_skipcomment(char_u *s) 5478 { 5479 while (*s) 5480 { 5481 char_u *prev_s = s; 5482 5483 s = skipwhite(s); 5484 5485 /* Perl/shell # comment comment continues until eol. Require a space 5486 * before # to avoid recognizing $#array. */ 5487 if (curbuf->b_ind_hash_comment != 0 && s != prev_s && *s == '#') 5488 { 5489 s += STRLEN(s); 5490 break; 5491 } 5492 if (*s != '/') 5493 break; 5494 ++s; 5495 if (*s == '/') /* slash-slash comment continues till eol */ 5496 { 5497 s += STRLEN(s); 5498 break; 5499 } 5500 if (*s != '*') 5501 break; 5502 for (++s; *s; ++s) /* skip slash-star comment */ 5503 if (s[0] == '*' && s[1] == '/') 5504 { 5505 s += 2; 5506 break; 5507 } 5508 } 5509 return s; 5510 } 5511 5512 /* 5513 * Return TRUE if there is no code at *s. White space and comments are 5514 * not considered code. 5515 */ 5516 static int 5517 cin_nocode(char_u *s) 5518 { 5519 return *cin_skipcomment(s) == NUL; 5520 } 5521 5522 /* 5523 * Check previous lines for a "//" line comment, skipping over blank lines. 5524 */ 5525 static pos_T * 5526 find_line_comment(void) /* XXX */ 5527 { 5528 static pos_T pos; 5529 char_u *line; 5530 char_u *p; 5531 5532 pos = curwin->w_cursor; 5533 while (--pos.lnum > 0) 5534 { 5535 line = ml_get(pos.lnum); 5536 p = skipwhite(line); 5537 if (cin_islinecomment(p)) 5538 { 5539 pos.col = (int)(p - line); 5540 return &pos; 5541 } 5542 if (*p != NUL) 5543 break; 5544 } 5545 return NULL; 5546 } 5547 5548 /* 5549 * Return TRUE if "text" starts with "key:". 5550 */ 5551 static int 5552 cin_has_js_key(char_u *text) 5553 { 5554 char_u *s = skipwhite(text); 5555 int quote = -1; 5556 5557 if (*s == '\'' || *s == '"') 5558 { 5559 /* can be 'key': or "key": */ 5560 quote = *s; 5561 ++s; 5562 } 5563 if (!vim_isIDc(*s)) /* need at least one ID character */ 5564 return FALSE; 5565 5566 while (vim_isIDc(*s)) 5567 ++s; 5568 if (*s == quote) 5569 ++s; 5570 5571 s = cin_skipcomment(s); 5572 5573 /* "::" is not a label, it's C++ */ 5574 return (*s == ':' && s[1] != ':'); 5575 } 5576 5577 /* 5578 * Check if string matches "label:"; move to character after ':' if true. 5579 * "*s" must point to the start of the label, if there is one. 5580 */ 5581 static int 5582 cin_islabel_skip(char_u **s) 5583 { 5584 if (!vim_isIDc(**s)) /* need at least one ID character */ 5585 return FALSE; 5586 5587 while (vim_isIDc(**s)) 5588 (*s)++; 5589 5590 *s = cin_skipcomment(*s); 5591 5592 /* "::" is not a label, it's C++ */ 5593 return (**s == ':' && *++*s != ':'); 5594 } 5595 5596 /* 5597 * Recognize a label: "label:". 5598 * Note: curwin->w_cursor must be where we are looking for the label. 5599 */ 5600 int 5601 cin_islabel(void) /* XXX */ 5602 { 5603 char_u *s; 5604 5605 s = cin_skipcomment(ml_get_curline()); 5606 5607 /* 5608 * Exclude "default" from labels, since it should be indented 5609 * like a switch label. Same for C++ scope declarations. 5610 */ 5611 if (cin_isdefault(s)) 5612 return FALSE; 5613 if (cin_isscopedecl(s)) 5614 return FALSE; 5615 5616 if (cin_islabel_skip(&s)) 5617 { 5618 /* 5619 * Only accept a label if the previous line is terminated or is a case 5620 * label. 5621 */ 5622 pos_T cursor_save; 5623 pos_T *trypos; 5624 char_u *line; 5625 5626 cursor_save = curwin->w_cursor; 5627 while (curwin->w_cursor.lnum > 1) 5628 { 5629 --curwin->w_cursor.lnum; 5630 5631 /* 5632 * If we're in a comment or raw string now, skip to the start of 5633 * it. 5634 */ 5635 curwin->w_cursor.col = 0; 5636 if ((trypos = ind_find_start_CORS()) != NULL) /* XXX */ 5637 curwin->w_cursor = *trypos; 5638 5639 line = ml_get_curline(); 5640 if (cin_ispreproc(line)) /* ignore #defines, #if, etc. */ 5641 continue; 5642 if (*(line = cin_skipcomment(line)) == NUL) 5643 continue; 5644 5645 curwin->w_cursor = cursor_save; 5646 if (cin_isterminated(line, TRUE, FALSE) 5647 || cin_isscopedecl(line) 5648 || cin_iscase(line, TRUE) 5649 || (cin_islabel_skip(&line) && cin_nocode(line))) 5650 return TRUE; 5651 return FALSE; 5652 } 5653 curwin->w_cursor = cursor_save; 5654 return TRUE; /* label at start of file??? */ 5655 } 5656 return FALSE; 5657 } 5658 5659 /* 5660 * Recognize structure initialization and enumerations: 5661 * "[typedef] [static|public|protected|private] enum" 5662 * "[typedef] [static|public|protected|private] = {" 5663 */ 5664 static int 5665 cin_isinit(void) 5666 { 5667 char_u *s; 5668 static char *skip[] = {"static", "public", "protected", "private"}; 5669 5670 s = cin_skipcomment(ml_get_curline()); 5671 5672 if (cin_starts_with(s, "typedef")) 5673 s = cin_skipcomment(s + 7); 5674 5675 for (;;) 5676 { 5677 int i, l; 5678 5679 for (i = 0; i < (int)(sizeof(skip) / sizeof(char *)); ++i) 5680 { 5681 l = (int)strlen(skip[i]); 5682 if (cin_starts_with(s, skip[i])) 5683 { 5684 s = cin_skipcomment(s + l); 5685 l = 0; 5686 break; 5687 } 5688 } 5689 if (l != 0) 5690 break; 5691 } 5692 5693 if (cin_starts_with(s, "enum")) 5694 return TRUE; 5695 5696 if (cin_ends_in(s, (char_u *)"=", (char_u *)"{")) 5697 return TRUE; 5698 5699 return FALSE; 5700 } 5701 5702 /* 5703 * Recognize a switch label: "case .*:" or "default:". 5704 */ 5705 int 5706 cin_iscase( 5707 char_u *s, 5708 int strict) /* Allow relaxed check of case statement for JS */ 5709 { 5710 s = cin_skipcomment(s); 5711 if (cin_starts_with(s, "case")) 5712 { 5713 for (s += 4; *s; ++s) 5714 { 5715 s = cin_skipcomment(s); 5716 if (*s == ':') 5717 { 5718 if (s[1] == ':') /* skip over "::" for C++ */ 5719 ++s; 5720 else 5721 return TRUE; 5722 } 5723 if (*s == '\'' && s[1] && s[2] == '\'') 5724 s += 2; /* skip over ':' */ 5725 else if (*s == '/' && (s[1] == '*' || s[1] == '/')) 5726 return FALSE; /* stop at comment */ 5727 else if (*s == '"') 5728 { 5729 /* JS etc. */ 5730 if (strict) 5731 return FALSE; /* stop at string */ 5732 else 5733 return TRUE; 5734 } 5735 } 5736 return FALSE; 5737 } 5738 5739 if (cin_isdefault(s)) 5740 return TRUE; 5741 return FALSE; 5742 } 5743 5744 /* 5745 * Recognize a "default" switch label. 5746 */ 5747 static int 5748 cin_isdefault(char_u *s) 5749 { 5750 return (STRNCMP(s, "default", 7) == 0 5751 && *(s = cin_skipcomment(s + 7)) == ':' 5752 && s[1] != ':'); 5753 } 5754 5755 /* 5756 * Recognize a "public/private/protected" scope declaration label. 5757 */ 5758 int 5759 cin_isscopedecl(char_u *s) 5760 { 5761 int i; 5762 5763 s = cin_skipcomment(s); 5764 if (STRNCMP(s, "public", 6) == 0) 5765 i = 6; 5766 else if (STRNCMP(s, "protected", 9) == 0) 5767 i = 9; 5768 else if (STRNCMP(s, "private", 7) == 0) 5769 i = 7; 5770 else 5771 return FALSE; 5772 return (*(s = cin_skipcomment(s + i)) == ':' && s[1] != ':'); 5773 } 5774 5775 /* Maximum number of lines to search back for a "namespace" line. */ 5776 #define FIND_NAMESPACE_LIM 20 5777 5778 /* 5779 * Recognize a "namespace" scope declaration. 5780 */ 5781 static int 5782 cin_is_cpp_namespace(char_u *s) 5783 { 5784 char_u *p; 5785 int has_name = FALSE; 5786 int has_name_start = FALSE; 5787 5788 s = cin_skipcomment(s); 5789 if (STRNCMP(s, "namespace", 9) == 0 && (s[9] == NUL || !vim_iswordc(s[9]))) 5790 { 5791 p = cin_skipcomment(skipwhite(s + 9)); 5792 while (*p != NUL) 5793 { 5794 if (VIM_ISWHITE(*p)) 5795 { 5796 has_name = TRUE; /* found end of a name */ 5797 p = cin_skipcomment(skipwhite(p)); 5798 } 5799 else if (*p == '{') 5800 { 5801 break; 5802 } 5803 else if (vim_iswordc(*p)) 5804 { 5805 has_name_start = TRUE; 5806 if (has_name) 5807 return FALSE; /* word character after skipping past name */ 5808 ++p; 5809 } 5810 else if (p[0] == ':' && p[1] == ':' && vim_iswordc(p[2])) 5811 { 5812 if (!has_name_start || has_name) 5813 return FALSE; 5814 /* C++ 17 nested namespace */ 5815 p += 3; 5816 } 5817 else 5818 { 5819 return FALSE; 5820 } 5821 } 5822 return TRUE; 5823 } 5824 return FALSE; 5825 } 5826 5827 /* 5828 * Recognize a `extern "C"` or `extern "C++"` linkage specifications. 5829 */ 5830 static int 5831 cin_is_cpp_extern_c(char_u *s) 5832 { 5833 char_u *p; 5834 int has_string_literal = FALSE; 5835 5836 s = cin_skipcomment(s); 5837 if (STRNCMP(s, "extern", 6) == 0 && (s[6] == NUL || !vim_iswordc(s[6]))) 5838 { 5839 p = cin_skipcomment(skipwhite(s + 6)); 5840 while (*p != NUL) 5841 { 5842 if (VIM_ISWHITE(*p)) 5843 { 5844 p = cin_skipcomment(skipwhite(p)); 5845 } 5846 else if (*p == '{') 5847 { 5848 break; 5849 } 5850 else if (p[0] == '"' && p[1] == 'C' && p[2] == '"') 5851 { 5852 if (has_string_literal) 5853 return FALSE; 5854 has_string_literal = TRUE; 5855 p += 3; 5856 } 5857 else if (p[0] == '"' && p[1] == 'C' && p[2] == '+' && p[3] == '+' 5858 && p[4] == '"') 5859 { 5860 if (has_string_literal) 5861 return FALSE; 5862 has_string_literal = TRUE; 5863 p += 5; 5864 } 5865 else 5866 { 5867 return FALSE; 5868 } 5869 } 5870 return has_string_literal ? TRUE : FALSE; 5871 } 5872 return FALSE; 5873 } 5874 5875 /* 5876 * Return a pointer to the first non-empty non-comment character after a ':'. 5877 * Return NULL if not found. 5878 * case 234: a = b; 5879 * ^ 5880 */ 5881 static char_u * 5882 after_label(char_u *l) 5883 { 5884 for ( ; *l; ++l) 5885 { 5886 if (*l == ':') 5887 { 5888 if (l[1] == ':') /* skip over "::" for C++ */ 5889 ++l; 5890 else if (!cin_iscase(l + 1, FALSE)) 5891 break; 5892 } 5893 else if (*l == '\'' && l[1] && l[2] == '\'') 5894 l += 2; /* skip over 'x' */ 5895 } 5896 if (*l == NUL) 5897 return NULL; 5898 l = cin_skipcomment(l + 1); 5899 if (*l == NUL) 5900 return NULL; 5901 return l; 5902 } 5903 5904 /* 5905 * Get indent of line "lnum", skipping a label. 5906 * Return 0 if there is nothing after the label. 5907 */ 5908 static int 5909 get_indent_nolabel (linenr_T lnum) /* XXX */ 5910 { 5911 char_u *l; 5912 pos_T fp; 5913 colnr_T col; 5914 char_u *p; 5915 5916 l = ml_get(lnum); 5917 p = after_label(l); 5918 if (p == NULL) 5919 return 0; 5920 5921 fp.col = (colnr_T)(p - l); 5922 fp.lnum = lnum; 5923 getvcol(curwin, &fp, &col, NULL, NULL); 5924 return (int)col; 5925 } 5926 5927 /* 5928 * Find indent for line "lnum", ignoring any case or jump label. 5929 * Also return a pointer to the text (after the label) in "pp". 5930 * label: if (asdf && asdfasdf) 5931 * ^ 5932 */ 5933 static int 5934 skip_label(linenr_T lnum, char_u **pp) 5935 { 5936 char_u *l; 5937 int amount; 5938 pos_T cursor_save; 5939 5940 cursor_save = curwin->w_cursor; 5941 curwin->w_cursor.lnum = lnum; 5942 l = ml_get_curline(); 5943 /* XXX */ 5944 if (cin_iscase(l, FALSE) || cin_isscopedecl(l) || cin_islabel()) 5945 { 5946 amount = get_indent_nolabel(lnum); 5947 l = after_label(ml_get_curline()); 5948 if (l == NULL) /* just in case */ 5949 l = ml_get_curline(); 5950 } 5951 else 5952 { 5953 amount = get_indent(); 5954 l = ml_get_curline(); 5955 } 5956 *pp = l; 5957 5958 curwin->w_cursor = cursor_save; 5959 return amount; 5960 } 5961 5962 /* 5963 * Return the indent of the first variable name after a type in a declaration. 5964 * int a, indent of "a" 5965 * static struct foo b, indent of "b" 5966 * enum bla c, indent of "c" 5967 * Returns zero when it doesn't look like a declaration. 5968 */ 5969 static int 5970 cin_first_id_amount(void) 5971 { 5972 char_u *line, *p, *s; 5973 int len; 5974 pos_T fp; 5975 colnr_T col; 5976 5977 line = ml_get_curline(); 5978 p = skipwhite(line); 5979 len = (int)(skiptowhite(p) - p); 5980 if (len == 6 && STRNCMP(p, "static", 6) == 0) 5981 { 5982 p = skipwhite(p + 6); 5983 len = (int)(skiptowhite(p) - p); 5984 } 5985 if (len == 6 && STRNCMP(p, "struct", 6) == 0) 5986 p = skipwhite(p + 6); 5987 else if (len == 4 && STRNCMP(p, "enum", 4) == 0) 5988 p = skipwhite(p + 4); 5989 else if ((len == 8 && STRNCMP(p, "unsigned", 8) == 0) 5990 || (len == 6 && STRNCMP(p, "signed", 6) == 0)) 5991 { 5992 s = skipwhite(p + len); 5993 if ((STRNCMP(s, "int", 3) == 0 && VIM_ISWHITE(s[3])) 5994 || (STRNCMP(s, "long", 4) == 0 && VIM_ISWHITE(s[4])) 5995 || (STRNCMP(s, "short", 5) == 0 && VIM_ISWHITE(s[5])) 5996 || (STRNCMP(s, "char", 4) == 0 && VIM_ISWHITE(s[4]))) 5997 p = s; 5998 } 5999 for (len = 0; vim_isIDc(p[len]); ++len) 6000 ; 6001 if (len == 0 || !VIM_ISWHITE(p[len]) || cin_nocode(p)) 6002 return 0; 6003 6004 p = skipwhite(p + len); 6005 fp.lnum = curwin->w_cursor.lnum; 6006 fp.col = (colnr_T)(p - line); 6007 getvcol(curwin, &fp, &col, NULL, NULL); 6008 return (int)col; 6009 } 6010 6011 /* 6012 * Return the indent of the first non-blank after an equal sign. 6013 * char *foo = "here"; 6014 * Return zero if no (useful) equal sign found. 6015 * Return -1 if the line above "lnum" ends in a backslash. 6016 * foo = "asdf\ 6017 * asdf\ 6018 * here"; 6019 */ 6020 static int 6021 cin_get_equal_amount(linenr_T lnum) 6022 { 6023 char_u *line; 6024 char_u *s; 6025 colnr_T col; 6026 pos_T fp; 6027 6028 if (lnum > 1) 6029 { 6030 line = ml_get(lnum - 1); 6031 if (*line != NUL && line[STRLEN(line) - 1] == '\\') 6032 return -1; 6033 } 6034 6035 line = s = ml_get(lnum); 6036 while (*s != NUL && vim_strchr((char_u *)"=;{}\"'", *s) == NULL) 6037 { 6038 if (cin_iscomment(s)) /* ignore comments */ 6039 s = cin_skipcomment(s); 6040 else 6041 ++s; 6042 } 6043 if (*s != '=') 6044 return 0; 6045 6046 s = skipwhite(s + 1); 6047 if (cin_nocode(s)) 6048 return 0; 6049 6050 if (*s == '"') /* nice alignment for continued strings */ 6051 ++s; 6052 6053 fp.lnum = lnum; 6054 fp.col = (colnr_T)(s - line); 6055 getvcol(curwin, &fp, &col, NULL, NULL); 6056 return (int)col; 6057 } 6058 6059 /* 6060 * Recognize a preprocessor statement: Any line that starts with '#'. 6061 */ 6062 static int 6063 cin_ispreproc(char_u *s) 6064 { 6065 if (*skipwhite(s) == '#') 6066 return TRUE; 6067 return FALSE; 6068 } 6069 6070 /* 6071 * Return TRUE if line "*pp" at "*lnump" is a preprocessor statement or a 6072 * continuation line of a preprocessor statement. Decrease "*lnump" to the 6073 * start and return the line in "*pp". 6074 * Put the amount of indent in "*amount". 6075 */ 6076 static int 6077 cin_ispreproc_cont(char_u **pp, linenr_T *lnump, int *amount) 6078 { 6079 char_u *line = *pp; 6080 linenr_T lnum = *lnump; 6081 int retval = FALSE; 6082 int candidate_amount = *amount; 6083 6084 if (*line != NUL && line[STRLEN(line) - 1] == '\\') 6085 candidate_amount = get_indent_lnum(lnum); 6086 6087 for (;;) 6088 { 6089 if (cin_ispreproc(line)) 6090 { 6091 retval = TRUE; 6092 *lnump = lnum; 6093 break; 6094 } 6095 if (lnum == 1) 6096 break; 6097 line = ml_get(--lnum); 6098 if (*line == NUL || line[STRLEN(line) - 1] != '\\') 6099 break; 6100 } 6101 6102 if (lnum != *lnump) 6103 *pp = ml_get(*lnump); 6104 if (retval) 6105 *amount = candidate_amount; 6106 return retval; 6107 } 6108 6109 /* 6110 * Recognize the start of a C or C++ comment. 6111 */ 6112 static int 6113 cin_iscomment(char_u *p) 6114 { 6115 return (p[0] == '/' && (p[1] == '*' || p[1] == '/')); 6116 } 6117 6118 /* 6119 * Recognize the start of a "//" comment. 6120 */ 6121 static int 6122 cin_islinecomment(char_u *p) 6123 { 6124 return (p[0] == '/' && p[1] == '/'); 6125 } 6126 6127 /* 6128 * Recognize a line that starts with '{' or '}', or ends with ';', ',', '{' or 6129 * '}'. 6130 * Don't consider "} else" a terminated line. 6131 * If a line begins with an "else", only consider it terminated if no unmatched 6132 * opening braces follow (handle "else { foo();" correctly). 6133 * Return the character terminating the line (ending char's have precedence if 6134 * both apply in order to determine initializations). 6135 */ 6136 static int 6137 cin_isterminated( 6138 char_u *s, 6139 int incl_open, /* include '{' at the end as terminator */ 6140 int incl_comma) /* recognize a trailing comma */ 6141 { 6142 char_u found_start = 0; 6143 unsigned n_open = 0; 6144 int is_else = FALSE; 6145 6146 s = cin_skipcomment(s); 6147 6148 if (*s == '{' || (*s == '}' && !cin_iselse(s))) 6149 found_start = *s; 6150 6151 if (!found_start) 6152 is_else = cin_iselse(s); 6153 6154 while (*s) 6155 { 6156 /* skip over comments, "" strings and 'c'haracters */ 6157 s = skip_string(cin_skipcomment(s)); 6158 if (*s == '}' && n_open > 0) 6159 --n_open; 6160 if ((!is_else || n_open == 0) 6161 && (*s == ';' || *s == '}' || (incl_comma && *s == ',')) 6162 && cin_nocode(s + 1)) 6163 return *s; 6164 else if (*s == '{') 6165 { 6166 if (incl_open && cin_nocode(s + 1)) 6167 return *s; 6168 else 6169 ++n_open; 6170 } 6171 6172 if (*s) 6173 s++; 6174 } 6175 return found_start; 6176 } 6177 6178 /* 6179 * Recognize the basic picture of a function declaration -- it needs to 6180 * have an open paren somewhere and a close paren at the end of the line and 6181 * no semicolons anywhere. 6182 * When a line ends in a comma we continue looking in the next line. 6183 * "sp" points to a string with the line. When looking at other lines it must 6184 * be restored to the line. When it's NULL fetch lines here. 6185 * "first_lnum" is where we start looking. 6186 * "min_lnum" is the line before which we will not be looking. 6187 */ 6188 static int 6189 cin_isfuncdecl( 6190 char_u **sp, 6191 linenr_T first_lnum, 6192 linenr_T min_lnum) 6193 { 6194 char_u *s; 6195 linenr_T lnum = first_lnum; 6196 linenr_T save_lnum = curwin->w_cursor.lnum; 6197 int retval = FALSE; 6198 pos_T *trypos; 6199 int just_started = TRUE; 6200 6201 if (sp == NULL) 6202 s = ml_get(lnum); 6203 else 6204 s = *sp; 6205 6206 curwin->w_cursor.lnum = lnum; 6207 if (find_last_paren(s, '(', ')') 6208 && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) 6209 { 6210 lnum = trypos->lnum; 6211 if (lnum < min_lnum) 6212 { 6213 curwin->w_cursor.lnum = save_lnum; 6214 return FALSE; 6215 } 6216 6217 s = ml_get(lnum); 6218 } 6219 curwin->w_cursor.lnum = save_lnum; 6220 6221 /* Ignore line starting with #. */ 6222 if (cin_ispreproc(s)) 6223 return FALSE; 6224 6225 while (*s && *s != '(' && *s != ';' && *s != '\'' && *s != '"') 6226 { 6227 if (cin_iscomment(s)) /* ignore comments */ 6228 s = cin_skipcomment(s); 6229 else if (*s == ':') 6230 { 6231 if (*(s + 1) == ':') 6232 s += 2; 6233 else 6234 /* To avoid a mistake in the following situation: 6235 * A::A(int a, int b) 6236 * : a(0) // <--not a function decl 6237 * , b(0) 6238 * {... 6239 */ 6240 return FALSE; 6241 } 6242 else 6243 ++s; 6244 } 6245 if (*s != '(') 6246 return FALSE; /* ';', ' or " before any () or no '(' */ 6247 6248 while (*s && *s != ';' && *s != '\'' && *s != '"') 6249 { 6250 if (*s == ')' && cin_nocode(s + 1)) 6251 { 6252 /* ')' at the end: may have found a match 6253 * Check for he previous line not to end in a backslash: 6254 * #if defined(x) && \ 6255 * defined(y) 6256 */ 6257 lnum = first_lnum - 1; 6258 s = ml_get(lnum); 6259 if (*s == NUL || s[STRLEN(s) - 1] != '\\') 6260 retval = TRUE; 6261 goto done; 6262 } 6263 if ((*s == ',' && cin_nocode(s + 1)) || s[1] == NUL || cin_nocode(s)) 6264 { 6265 int comma = (*s == ','); 6266 6267 /* ',' at the end: continue looking in the next line. 6268 * At the end: check for ',' in the next line, for this style: 6269 * func(arg1 6270 * , arg2) */ 6271 for (;;) 6272 { 6273 if (lnum >= curbuf->b_ml.ml_line_count) 6274 break; 6275 s = ml_get(++lnum); 6276 if (!cin_ispreproc(s)) 6277 break; 6278 } 6279 if (lnum >= curbuf->b_ml.ml_line_count) 6280 break; 6281 /* Require a comma at end of the line or a comma or ')' at the 6282 * start of next line. */ 6283 s = skipwhite(s); 6284 if (!just_started && (!comma && *s != ',' && *s != ')')) 6285 break; 6286 just_started = FALSE; 6287 } 6288 else if (cin_iscomment(s)) /* ignore comments */ 6289 s = cin_skipcomment(s); 6290 else 6291 { 6292 ++s; 6293 just_started = FALSE; 6294 } 6295 } 6296 6297 done: 6298 if (lnum != first_lnum && sp != NULL) 6299 *sp = ml_get(first_lnum); 6300 6301 return retval; 6302 } 6303 6304 static int 6305 cin_isif(char_u *p) 6306 { 6307 return (STRNCMP(p, "if", 2) == 0 && !vim_isIDc(p[2])); 6308 } 6309 6310 static int 6311 cin_iselse( 6312 char_u *p) 6313 { 6314 if (*p == '}') /* accept "} else" */ 6315 p = cin_skipcomment(p + 1); 6316 return (STRNCMP(p, "else", 4) == 0 && !vim_isIDc(p[4])); 6317 } 6318 6319 static int 6320 cin_isdo(char_u *p) 6321 { 6322 return (STRNCMP(p, "do", 2) == 0 && !vim_isIDc(p[2])); 6323 } 6324 6325 /* 6326 * Check if this is a "while" that should have a matching "do". 6327 * We only accept a "while (condition) ;", with only white space between the 6328 * ')' and ';'. The condition may be spread over several lines. 6329 */ 6330 static int 6331 cin_iswhileofdo (char_u *p, linenr_T lnum) /* XXX */ 6332 { 6333 pos_T cursor_save; 6334 pos_T *trypos; 6335 int retval = FALSE; 6336 6337 p = cin_skipcomment(p); 6338 if (*p == '}') /* accept "} while (cond);" */ 6339 p = cin_skipcomment(p + 1); 6340 if (cin_starts_with(p, "while")) 6341 { 6342 cursor_save = curwin->w_cursor; 6343 curwin->w_cursor.lnum = lnum; 6344 curwin->w_cursor.col = 0; 6345 p = ml_get_curline(); 6346 while (*p && *p != 'w') /* skip any '}', until the 'w' of the "while" */ 6347 { 6348 ++p; 6349 ++curwin->w_cursor.col; 6350 } 6351 if ((trypos = findmatchlimit(NULL, 0, 0, 6352 curbuf->b_ind_maxparen)) != NULL 6353 && *cin_skipcomment(ml_get_pos(trypos) + 1) == ';') 6354 retval = TRUE; 6355 curwin->w_cursor = cursor_save; 6356 } 6357 return retval; 6358 } 6359 6360 /* 6361 * Check whether in "p" there is an "if", "for" or "while" before "*poffset". 6362 * Return 0 if there is none. 6363 * Otherwise return !0 and update "*poffset" to point to the place where the 6364 * string was found. 6365 */ 6366 static int 6367 cin_is_if_for_while_before_offset(char_u *line, int *poffset) 6368 { 6369 int offset = *poffset; 6370 6371 if (offset-- < 2) 6372 return 0; 6373 while (offset > 2 && VIM_ISWHITE(line[offset])) 6374 --offset; 6375 6376 offset -= 1; 6377 if (!STRNCMP(line + offset, "if", 2)) 6378 goto probablyFound; 6379 6380 if (offset >= 1) 6381 { 6382 offset -= 1; 6383 if (!STRNCMP(line + offset, "for", 3)) 6384 goto probablyFound; 6385 6386 if (offset >= 2) 6387 { 6388 offset -= 2; 6389 if (!STRNCMP(line + offset, "while", 5)) 6390 goto probablyFound; 6391 } 6392 } 6393 return 0; 6394 6395 probablyFound: 6396 if (!offset || !vim_isIDc(line[offset - 1])) 6397 { 6398 *poffset = offset; 6399 return 1; 6400 } 6401 return 0; 6402 } 6403 6404 /* 6405 * Return TRUE if we are at the end of a do-while. 6406 * do 6407 * nothing; 6408 * while (foo 6409 * && bar); <-- here 6410 * Adjust the cursor to the line with "while". 6411 */ 6412 static int 6413 cin_iswhileofdo_end(int terminated) 6414 { 6415 char_u *line; 6416 char_u *p; 6417 char_u *s; 6418 pos_T *trypos; 6419 int i; 6420 6421 if (terminated != ';') /* there must be a ';' at the end */ 6422 return FALSE; 6423 6424 p = line = ml_get_curline(); 6425 while (*p != NUL) 6426 { 6427 p = cin_skipcomment(p); 6428 if (*p == ')') 6429 { 6430 s = skipwhite(p + 1); 6431 if (*s == ';' && cin_nocode(s + 1)) 6432 { 6433 /* Found ");" at end of the line, now check there is "while" 6434 * before the matching '('. XXX */ 6435 i = (int)(p - line); 6436 curwin->w_cursor.col = i; 6437 trypos = find_match_paren(curbuf->b_ind_maxparen); 6438 if (trypos != NULL) 6439 { 6440 s = cin_skipcomment(ml_get(trypos->lnum)); 6441 if (*s == '}') /* accept "} while (cond);" */ 6442 s = cin_skipcomment(s + 1); 6443 if (cin_starts_with(s, "while")) 6444 { 6445 curwin->w_cursor.lnum = trypos->lnum; 6446 return TRUE; 6447 } 6448 } 6449 6450 /* Searching may have made "line" invalid, get it again. */ 6451 line = ml_get_curline(); 6452 p = line + i; 6453 } 6454 } 6455 if (*p != NUL) 6456 ++p; 6457 } 6458 return FALSE; 6459 } 6460 6461 static int 6462 cin_isbreak(char_u *p) 6463 { 6464 return (STRNCMP(p, "break", 5) == 0 && !vim_isIDc(p[5])); 6465 } 6466 6467 /* 6468 * Find the position of a C++ base-class declaration or 6469 * constructor-initialization. eg: 6470 * 6471 * class MyClass : 6472 * baseClass <-- here 6473 * class MyClass : public baseClass, 6474 * anotherBaseClass <-- here (should probably lineup ??) 6475 * MyClass::MyClass(...) : 6476 * baseClass(...) <-- here (constructor-initialization) 6477 * 6478 * This is a lot of guessing. Watch out for "cond ? func() : foo". 6479 */ 6480 static int 6481 cin_is_cpp_baseclass( 6482 cpp_baseclass_cache_T *cached) /* input and output */ 6483 { 6484 lpos_T *pos = &cached->lpos; /* find position */ 6485 char_u *s; 6486 int class_or_struct, lookfor_ctor_init, cpp_base_class; 6487 linenr_T lnum = curwin->w_cursor.lnum; 6488 char_u *line = ml_get_curline(); 6489 6490 if (pos->lnum <= lnum) 6491 return cached->found; /* Use the cached result */ 6492 6493 pos->col = 0; 6494 6495 s = skipwhite(line); 6496 if (*s == '#') /* skip #define FOO x ? (x) : x */ 6497 return FALSE; 6498 s = cin_skipcomment(s); 6499 if (*s == NUL) 6500 return FALSE; 6501 6502 cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE; 6503 6504 /* Search for a line starting with '#', empty, ending in ';' or containing 6505 * '{' or '}' and start below it. This handles the following situations: 6506 * a = cond ? 6507 * func() : 6508 * asdf; 6509 * func::foo() 6510 * : something 6511 * {} 6512 * Foo::Foo (int one, int two) 6513 * : something(4), 6514 * somethingelse(3) 6515 * {} 6516 */ 6517 while (lnum > 1) 6518 { 6519 line = ml_get(lnum - 1); 6520 s = skipwhite(line); 6521 if (*s == '#' || *s == NUL) 6522 break; 6523 while (*s != NUL) 6524 { 6525 s = cin_skipcomment(s); 6526 if (*s == '{' || *s == '}' 6527 || (*s == ';' && cin_nocode(s + 1))) 6528 break; 6529 if (*s != NUL) 6530 ++s; 6531 } 6532 if (*s != NUL) 6533 break; 6534 --lnum; 6535 } 6536 6537 pos->lnum = lnum; 6538 line = ml_get(lnum); 6539 s = line; 6540 for (;;) 6541 { 6542 if (*s == NUL) 6543 { 6544 if (lnum == curwin->w_cursor.lnum) 6545 break; 6546 /* Continue in the cursor line. */ 6547 line = ml_get(++lnum); 6548 s = line; 6549 } 6550 if (s == line) 6551 { 6552 /* don't recognize "case (foo):" as a baseclass */ 6553 if (cin_iscase(s, FALSE)) 6554 break; 6555 s = cin_skipcomment(line); 6556 if (*s == NUL) 6557 continue; 6558 } 6559 6560 if (s[0] == '"' || (s[0] == 'R' && s[1] == '"')) 6561 s = skip_string(s) + 1; 6562 else if (s[0] == ':') 6563 { 6564 if (s[1] == ':') 6565 { 6566 /* skip double colon. It can't be a constructor 6567 * initialization any more */ 6568 lookfor_ctor_init = FALSE; 6569 s = cin_skipcomment(s + 2); 6570 } 6571 else if (lookfor_ctor_init || class_or_struct) 6572 { 6573 /* we have something found, that looks like the start of 6574 * cpp-base-class-declaration or constructor-initialization */ 6575 cpp_base_class = TRUE; 6576 lookfor_ctor_init = class_or_struct = FALSE; 6577 pos->col = 0; 6578 s = cin_skipcomment(s + 1); 6579 } 6580 else 6581 s = cin_skipcomment(s + 1); 6582 } 6583 else if ((STRNCMP(s, "class", 5) == 0 && !vim_isIDc(s[5])) 6584 || (STRNCMP(s, "struct", 6) == 0 && !vim_isIDc(s[6]))) 6585 { 6586 class_or_struct = TRUE; 6587 lookfor_ctor_init = FALSE; 6588 6589 if (*s == 'c') 6590 s = cin_skipcomment(s + 5); 6591 else 6592 s = cin_skipcomment(s + 6); 6593 } 6594 else 6595 { 6596 if (s[0] == '{' || s[0] == '}' || s[0] == ';') 6597 { 6598 cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE; 6599 } 6600 else if (s[0] == ')') 6601 { 6602 /* Constructor-initialization is assumed if we come across 6603 * something like "):" */ 6604 class_or_struct = FALSE; 6605 lookfor_ctor_init = TRUE; 6606 } 6607 else if (s[0] == '?') 6608 { 6609 /* Avoid seeing '() :' after '?' as constructor init. */ 6610 return FALSE; 6611 } 6612 else if (!vim_isIDc(s[0])) 6613 { 6614 /* if it is not an identifier, we are wrong */ 6615 class_or_struct = FALSE; 6616 lookfor_ctor_init = FALSE; 6617 } 6618 else if (pos->col == 0) 6619 { 6620 /* it can't be a constructor-initialization any more */ 6621 lookfor_ctor_init = FALSE; 6622 6623 /* the first statement starts here: lineup with this one... */ 6624 if (cpp_base_class) 6625 pos->col = (colnr_T)(s - line); 6626 } 6627 6628 /* When the line ends in a comma don't align with it. */ 6629 if (lnum == curwin->w_cursor.lnum && *s == ',' && cin_nocode(s + 1)) 6630 pos->col = 0; 6631 6632 s = cin_skipcomment(s + 1); 6633 } 6634 } 6635 6636 cached->found = cpp_base_class; 6637 if (cpp_base_class) 6638 pos->lnum = lnum; 6639 return cpp_base_class; 6640 } 6641 6642 static int 6643 get_baseclass_amount(int col) 6644 { 6645 int amount; 6646 colnr_T vcol; 6647 pos_T *trypos; 6648 6649 if (col == 0) 6650 { 6651 amount = get_indent(); 6652 if (find_last_paren(ml_get_curline(), '(', ')') 6653 && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) 6654 amount = get_indent_lnum(trypos->lnum); /* XXX */ 6655 if (!cin_ends_in(ml_get_curline(), (char_u *)",", NULL)) 6656 amount += curbuf->b_ind_cpp_baseclass; 6657 } 6658 else 6659 { 6660 curwin->w_cursor.col = col; 6661 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); 6662 amount = (int)vcol; 6663 } 6664 if (amount < curbuf->b_ind_cpp_baseclass) 6665 amount = curbuf->b_ind_cpp_baseclass; 6666 return amount; 6667 } 6668 6669 /* 6670 * Return TRUE if string "s" ends with the string "find", possibly followed by 6671 * white space and comments. Skip strings and comments. 6672 * Ignore "ignore" after "find" if it's not NULL. 6673 */ 6674 static int 6675 cin_ends_in(char_u *s, char_u *find, char_u *ignore) 6676 { 6677 char_u *p = s; 6678 char_u *r; 6679 int len = (int)STRLEN(find); 6680 6681 while (*p != NUL) 6682 { 6683 p = cin_skipcomment(p); 6684 if (STRNCMP(p, find, len) == 0) 6685 { 6686 r = skipwhite(p + len); 6687 if (ignore != NULL && STRNCMP(r, ignore, STRLEN(ignore)) == 0) 6688 r = skipwhite(r + STRLEN(ignore)); 6689 if (cin_nocode(r)) 6690 return TRUE; 6691 } 6692 if (*p != NUL) 6693 ++p; 6694 } 6695 return FALSE; 6696 } 6697 6698 /* 6699 * Return TRUE when "s" starts with "word" and then a non-ID character. 6700 */ 6701 static int 6702 cin_starts_with(char_u *s, char *word) 6703 { 6704 int l = (int)STRLEN(word); 6705 6706 return (STRNCMP(s, word, l) == 0 && !vim_isIDc(s[l])); 6707 } 6708 6709 /* 6710 * Skip strings, chars and comments until at or past "trypos". 6711 * Return the column found. 6712 */ 6713 static int 6714 cin_skip2pos(pos_T *trypos) 6715 { 6716 char_u *line; 6717 char_u *p; 6718 char_u *new_p; 6719 6720 p = line = ml_get(trypos->lnum); 6721 while (*p && (colnr_T)(p - line) < trypos->col) 6722 { 6723 if (cin_iscomment(p)) 6724 p = cin_skipcomment(p); 6725 else 6726 { 6727 new_p = skip_string(p); 6728 if (new_p == p) 6729 ++p; 6730 else 6731 p = new_p; 6732 } 6733 } 6734 return (int)(p - line); 6735 } 6736 6737 /* 6738 * Find the '{' at the start of the block we are in. 6739 * Return NULL if no match found. 6740 * Ignore a '{' that is in a comment, makes indenting the next three lines 6741 * work. */ 6742 /* foo() */ 6743 /* { */ 6744 /* } */ 6745 6746 static pos_T * 6747 find_start_brace(void) /* XXX */ 6748 { 6749 pos_T cursor_save; 6750 pos_T *trypos; 6751 pos_T *pos; 6752 static pos_T pos_copy; 6753 6754 cursor_save = curwin->w_cursor; 6755 while ((trypos = findmatchlimit(NULL, '{', FM_BLOCKSTOP, 0)) != NULL) 6756 { 6757 pos_copy = *trypos; /* copy pos_T, next findmatch will change it */ 6758 trypos = &pos_copy; 6759 curwin->w_cursor = *trypos; 6760 pos = NULL; 6761 /* ignore the { if it's in a // or / * * / comment */ 6762 if ((colnr_T)cin_skip2pos(trypos) == trypos->col 6763 && (pos = ind_find_start_CORS()) == NULL) /* XXX */ 6764 break; 6765 if (pos != NULL) 6766 curwin->w_cursor.lnum = pos->lnum; 6767 } 6768 curwin->w_cursor = cursor_save; 6769 return trypos; 6770 } 6771 6772 /* 6773 * Find the matching '(', ignoring it if it is in a comment. 6774 * Return NULL if no match found. 6775 */ 6776 static pos_T * 6777 find_match_paren(int ind_maxparen) /* XXX */ 6778 { 6779 return find_match_char('(', ind_maxparen); 6780 } 6781 6782 static pos_T * 6783 find_match_char (int c, int ind_maxparen) /* XXX */ 6784 { 6785 pos_T cursor_save; 6786 pos_T *trypos; 6787 static pos_T pos_copy; 6788 int ind_maxp_wk; 6789 6790 cursor_save = curwin->w_cursor; 6791 ind_maxp_wk = ind_maxparen; 6792 retry: 6793 if ((trypos = findmatchlimit(NULL, c, 0, ind_maxp_wk)) != NULL) 6794 { 6795 /* check if the ( is in a // comment */ 6796 if ((colnr_T)cin_skip2pos(trypos) > trypos->col) 6797 { 6798 ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum - trypos->lnum); 6799 if (ind_maxp_wk > 0) 6800 { 6801 curwin->w_cursor = *trypos; 6802 curwin->w_cursor.col = 0; /* XXX */ 6803 goto retry; 6804 } 6805 trypos = NULL; 6806 } 6807 else 6808 { 6809 pos_T *trypos_wk; 6810 6811 pos_copy = *trypos; /* copy trypos, findmatch will change it */ 6812 trypos = &pos_copy; 6813 curwin->w_cursor = *trypos; 6814 if ((trypos_wk = ind_find_start_CORS()) != NULL) /* XXX */ 6815 { 6816 ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum 6817 - trypos_wk->lnum); 6818 if (ind_maxp_wk > 0) 6819 { 6820 curwin->w_cursor = *trypos_wk; 6821 goto retry; 6822 } 6823 trypos = NULL; 6824 } 6825 } 6826 } 6827 curwin->w_cursor = cursor_save; 6828 return trypos; 6829 } 6830 6831 /* 6832 * Find the matching '(', ignoring it if it is in a comment or before an 6833 * unmatched {. 6834 * Return NULL if no match found. 6835 */ 6836 static pos_T * 6837 find_match_paren_after_brace (int ind_maxparen) /* XXX */ 6838 { 6839 pos_T *trypos = find_match_paren(ind_maxparen); 6840 6841 if (trypos != NULL) 6842 { 6843 pos_T *tryposBrace = find_start_brace(); 6844 6845 /* If both an unmatched '(' and '{' is found. Ignore the '(' 6846 * position if the '{' is further down. */ 6847 if (tryposBrace != NULL 6848 && (trypos->lnum != tryposBrace->lnum 6849 ? trypos->lnum < tryposBrace->lnum 6850 : trypos->col < tryposBrace->col)) 6851 trypos = NULL; 6852 } 6853 return trypos; 6854 } 6855 6856 /* 6857 * Return ind_maxparen corrected for the difference in line number between the 6858 * cursor position and "startpos". This makes sure that searching for a 6859 * matching paren above the cursor line doesn't find a match because of 6860 * looking a few lines further. 6861 */ 6862 static int 6863 corr_ind_maxparen(pos_T *startpos) 6864 { 6865 long n = (long)startpos->lnum - (long)curwin->w_cursor.lnum; 6866 6867 if (n > 0 && n < curbuf->b_ind_maxparen / 2) 6868 return curbuf->b_ind_maxparen - (int)n; 6869 return curbuf->b_ind_maxparen; 6870 } 6871 6872 /* 6873 * Set w_cursor.col to the column number of the last unmatched ')' or '{' in 6874 * line "l". "l" must point to the start of the line. 6875 */ 6876 static int 6877 find_last_paren(char_u *l, int start, int end) 6878 { 6879 int i; 6880 int retval = FALSE; 6881 int open_count = 0; 6882 6883 curwin->w_cursor.col = 0; /* default is start of line */ 6884 6885 for (i = 0; l[i] != NUL; i++) 6886 { 6887 i = (int)(cin_skipcomment(l + i) - l); /* ignore parens in comments */ 6888 i = (int)(skip_string(l + i) - l); /* ignore parens in quotes */ 6889 if (l[i] == start) 6890 ++open_count; 6891 else if (l[i] == end) 6892 { 6893 if (open_count > 0) 6894 --open_count; 6895 else 6896 { 6897 curwin->w_cursor.col = i; 6898 retval = TRUE; 6899 } 6900 } 6901 } 6902 return retval; 6903 } 6904 6905 /* 6906 * Parse 'cinoptions' and set the values in "curbuf". 6907 * Must be called when 'cinoptions', 'shiftwidth' and/or 'tabstop' changes. 6908 */ 6909 void 6910 parse_cino(buf_T *buf) 6911 { 6912 char_u *p; 6913 char_u *l; 6914 char_u *digits; 6915 int n; 6916 int divider; 6917 int fraction = 0; 6918 int sw = (int)get_sw_value(buf); 6919 6920 /* 6921 * Set the default values. 6922 */ 6923 /* Spaces from a block's opening brace the prevailing indent for that 6924 * block should be. */ 6925 buf->b_ind_level = sw; 6926 6927 /* Spaces from the edge of the line an open brace that's at the end of a 6928 * line is imagined to be. */ 6929 buf->b_ind_open_imag = 0; 6930 6931 /* Spaces from the prevailing indent for a line that is not preceded by 6932 * an opening brace. */ 6933 buf->b_ind_no_brace = 0; 6934 6935 /* Column where the first { of a function should be located }. */ 6936 buf->b_ind_first_open = 0; 6937 6938 /* Spaces from the prevailing indent a leftmost open brace should be 6939 * located. */ 6940 buf->b_ind_open_extra = 0; 6941 6942 /* Spaces from the matching open brace (real location for one at the left 6943 * edge; imaginary location from one that ends a line) the matching close 6944 * brace should be located. */ 6945 buf->b_ind_close_extra = 0; 6946 6947 /* Spaces from the edge of the line an open brace sitting in the leftmost 6948 * column is imagined to be. */ 6949 buf->b_ind_open_left_imag = 0; 6950 6951 /* Spaces jump labels should be shifted to the left if N is non-negative, 6952 * otherwise the jump label will be put to column 1. */ 6953 buf->b_ind_jump_label = -1; 6954 6955 /* Spaces from the switch() indent a "case xx" label should be located. */ 6956 buf->b_ind_case = sw; 6957 6958 /* Spaces from the "case xx:" code after a switch() should be located. */ 6959 buf->b_ind_case_code = sw; 6960 6961 /* Lineup break at end of case in switch() with case label. */ 6962 buf->b_ind_case_break = 0; 6963 6964 /* Spaces from the class declaration indent a scope declaration label 6965 * should be located. */ 6966 buf->b_ind_scopedecl = sw; 6967 6968 /* Spaces from the scope declaration label code should be located. */ 6969 buf->b_ind_scopedecl_code = sw; 6970 6971 /* Amount K&R-style parameters should be indented. */ 6972 buf->b_ind_param = sw; 6973 6974 /* Amount a function type spec should be indented. */ 6975 buf->b_ind_func_type = sw; 6976 6977 /* Amount a cpp base class declaration or constructor initialization 6978 * should be indented. */ 6979 buf->b_ind_cpp_baseclass = sw; 6980 6981 /* additional spaces beyond the prevailing indent a continuation line 6982 * should be located. */ 6983 buf->b_ind_continuation = sw; 6984 6985 /* Spaces from the indent of the line with an unclosed parentheses. */ 6986 buf->b_ind_unclosed = sw * 2; 6987 6988 /* Spaces from the indent of the line with an unclosed parentheses, which 6989 * itself is also unclosed. */ 6990 buf->b_ind_unclosed2 = sw; 6991 6992 /* Suppress ignoring spaces from the indent of a line starting with an 6993 * unclosed parentheses. */ 6994 buf->b_ind_unclosed_noignore = 0; 6995 6996 /* If the opening paren is the last nonwhite character on the line, and 6997 * b_ind_unclosed_wrapped is nonzero, use this indent relative to the outer 6998 * context (for very long lines). */ 6999 buf->b_ind_unclosed_wrapped = 0; 7000 7001 /* Suppress ignoring white space when lining up with the character after 7002 * an unclosed parentheses. */ 7003 buf->b_ind_unclosed_whiteok = 0; 7004 7005 /* Indent a closing parentheses under the line start of the matching 7006 * opening parentheses. */ 7007 buf->b_ind_matching_paren = 0; 7008 7009 /* Indent a closing parentheses under the previous line. */ 7010 buf->b_ind_paren_prev = 0; 7011 7012 /* Extra indent for comments. */ 7013 buf->b_ind_comment = 0; 7014 7015 /* Spaces from the comment opener when there is nothing after it. */ 7016 buf->b_ind_in_comment = 3; 7017 7018 /* Boolean: if non-zero, use b_ind_in_comment even if there is something 7019 * after the comment opener. */ 7020 buf->b_ind_in_comment2 = 0; 7021 7022 /* Max lines to search for an open paren. */ 7023 buf->b_ind_maxparen = 20; 7024 7025 /* Max lines to search for an open comment. */ 7026 buf->b_ind_maxcomment = 70; 7027 7028 /* Handle braces for java code. */ 7029 buf->b_ind_java = 0; 7030 7031 /* Not to confuse JS object properties with labels. */ 7032 buf->b_ind_js = 0; 7033 7034 /* Handle blocked cases correctly. */ 7035 buf->b_ind_keep_case_label = 0; 7036 7037 /* Handle C++ namespace. */ 7038 buf->b_ind_cpp_namespace = 0; 7039 7040 /* Handle continuation lines containing conditions of if(), for() and 7041 * while(). */ 7042 buf->b_ind_if_for_while = 0; 7043 7044 /* indentation for # comments */ 7045 buf->b_ind_hash_comment = 0; 7046 7047 /* Handle C++ extern "C" or "C++" */ 7048 buf->b_ind_cpp_extern_c = 0; 7049 7050 for (p = buf->b_p_cino; *p; ) 7051 { 7052 l = p++; 7053 if (*p == '-') 7054 ++p; 7055 digits = p; /* remember where the digits start */ 7056 n = getdigits(&p); 7057 divider = 0; 7058 if (*p == '.') /* ".5s" means a fraction */ 7059 { 7060 fraction = atol((char *)++p); 7061 while (VIM_ISDIGIT(*p)) 7062 { 7063 ++p; 7064 if (divider) 7065 divider *= 10; 7066 else 7067 divider = 10; 7068 } 7069 } 7070 if (*p == 's') /* "2s" means two times 'shiftwidth' */ 7071 { 7072 if (p == digits) 7073 n = sw; /* just "s" is one 'shiftwidth' */ 7074 else 7075 { 7076 n *= sw; 7077 if (divider) 7078 n += (sw * fraction + divider / 2) / divider; 7079 } 7080 ++p; 7081 } 7082 if (l[1] == '-') 7083 n = -n; 7084 7085 /* When adding an entry here, also update the default 'cinoptions' in 7086 * doc/indent.txt, and add explanation for it! */ 7087 switch (*l) 7088 { 7089 case '>': buf->b_ind_level = n; break; 7090 case 'e': buf->b_ind_open_imag = n; break; 7091 case 'n': buf->b_ind_no_brace = n; break; 7092 case 'f': buf->b_ind_first_open = n; break; 7093 case '{': buf->b_ind_open_extra = n; break; 7094 case '}': buf->b_ind_close_extra = n; break; 7095 case '^': buf->b_ind_open_left_imag = n; break; 7096 case 'L': buf->b_ind_jump_label = n; break; 7097 case ':': buf->b_ind_case = n; break; 7098 case '=': buf->b_ind_case_code = n; break; 7099 case 'b': buf->b_ind_case_break = n; break; 7100 case 'p': buf->b_ind_param = n; break; 7101 case 't': buf->b_ind_func_type = n; break; 7102 case '/': buf->b_ind_comment = n; break; 7103 case 'c': buf->b_ind_in_comment = n; break; 7104 case 'C': buf->b_ind_in_comment2 = n; break; 7105 case 'i': buf->b_ind_cpp_baseclass = n; break; 7106 case '+': buf->b_ind_continuation = n; break; 7107 case '(': buf->b_ind_unclosed = n; break; 7108 case 'u': buf->b_ind_unclosed2 = n; break; 7109 case 'U': buf->b_ind_unclosed_noignore = n; break; 7110 case 'W': buf->b_ind_unclosed_wrapped = n; break; 7111 case 'w': buf->b_ind_unclosed_whiteok = n; break; 7112 case 'm': buf->b_ind_matching_paren = n; break; 7113 case 'M': buf->b_ind_paren_prev = n; break; 7114 case ')': buf->b_ind_maxparen = n; break; 7115 case '*': buf->b_ind_maxcomment = n; break; 7116 case 'g': buf->b_ind_scopedecl = n; break; 7117 case 'h': buf->b_ind_scopedecl_code = n; break; 7118 case 'j': buf->b_ind_java = n; break; 7119 case 'J': buf->b_ind_js = n; break; 7120 case 'l': buf->b_ind_keep_case_label = n; break; 7121 case '#': buf->b_ind_hash_comment = n; break; 7122 case 'N': buf->b_ind_cpp_namespace = n; break; 7123 case 'k': buf->b_ind_if_for_while = n; break; 7124 case 'E': buf->b_ind_cpp_extern_c = n; break; 7125 } 7126 if (*p == ',') 7127 ++p; 7128 } 7129 } 7130 7131 /* 7132 * Return the desired indent for C code. 7133 * Return -1 if the indent should be left alone (inside a raw string). 7134 */ 7135 int 7136 get_c_indent(void) 7137 { 7138 pos_T cur_curpos; 7139 int amount; 7140 int scope_amount; 7141 int cur_amount = MAXCOL; 7142 colnr_T col; 7143 char_u *theline; 7144 char_u *linecopy; 7145 pos_T *trypos; 7146 pos_T *comment_pos; 7147 pos_T *tryposBrace = NULL; 7148 pos_T tryposCopy; 7149 pos_T our_paren_pos; 7150 char_u *start; 7151 int start_brace; 7152 #define BRACE_IN_COL0 1 /* '{' is in column 0 */ 7153 #define BRACE_AT_START 2 /* '{' is at start of line */ 7154 #define BRACE_AT_END 3 /* '{' is at end of line */ 7155 linenr_T ourscope; 7156 char_u *l; 7157 char_u *look; 7158 char_u terminated; 7159 int lookfor; 7160 #define LOOKFOR_INITIAL 0 7161 #define LOOKFOR_IF 1 7162 #define LOOKFOR_DO 2 7163 #define LOOKFOR_CASE 3 7164 #define LOOKFOR_ANY 4 7165 #define LOOKFOR_TERM 5 7166 #define LOOKFOR_UNTERM 6 7167 #define LOOKFOR_SCOPEDECL 7 7168 #define LOOKFOR_NOBREAK 8 7169 #define LOOKFOR_CPP_BASECLASS 9 7170 #define LOOKFOR_ENUM_OR_INIT 10 7171 #define LOOKFOR_JS_KEY 11 7172 #define LOOKFOR_COMMA 12 7173 7174 int whilelevel; 7175 linenr_T lnum; 7176 int n; 7177 int iscase; 7178 int lookfor_break; 7179 int lookfor_cpp_namespace = FALSE; 7180 int cont_amount = 0; /* amount for continuation line */ 7181 int original_line_islabel; 7182 int added_to_amount = 0; 7183 int js_cur_has_key = 0; 7184 cpp_baseclass_cache_T cache_cpp_baseclass = { FALSE, { MAXLNUM, 0 } }; 7185 7186 /* make a copy, value is changed below */ 7187 int ind_continuation = curbuf->b_ind_continuation; 7188 7189 /* remember where the cursor was when we started */ 7190 cur_curpos = curwin->w_cursor; 7191 7192 /* if we are at line 1 zero indent is fine, right? */ 7193 if (cur_curpos.lnum == 1) 7194 return 0; 7195 7196 /* Get a copy of the current contents of the line. 7197 * This is required, because only the most recent line obtained with 7198 * ml_get is valid! */ 7199 linecopy = vim_strsave(ml_get(cur_curpos.lnum)); 7200 if (linecopy == NULL) 7201 return 0; 7202 7203 /* 7204 * In insert mode and the cursor is on a ')' truncate the line at the 7205 * cursor position. We don't want to line up with the matching '(' when 7206 * inserting new stuff. 7207 * For unknown reasons the cursor might be past the end of the line, thus 7208 * check for that. 7209 */ 7210 if ((State & INSERT) 7211 && curwin->w_cursor.col < (colnr_T)STRLEN(linecopy) 7212 && linecopy[curwin->w_cursor.col] == ')') 7213 linecopy[curwin->w_cursor.col] = NUL; 7214 7215 theline = skipwhite(linecopy); 7216 7217 /* move the cursor to the start of the line */ 7218 7219 curwin->w_cursor.col = 0; 7220 7221 original_line_islabel = cin_islabel(); /* XXX */ 7222 7223 /* 7224 * If we are inside a raw string don't change the indent. 7225 * Ignore a raw string inside a comment. 7226 */ 7227 comment_pos = ind_find_start_comment(); 7228 if (comment_pos != NULL) 7229 { 7230 /* findmatchlimit() static pos is overwritten, make a copy */ 7231 tryposCopy = *comment_pos; 7232 comment_pos = &tryposCopy; 7233 } 7234 trypos = find_start_rawstring(curbuf->b_ind_maxcomment); 7235 if (trypos != NULL && (comment_pos == NULL 7236 || LT_POS(*trypos, *comment_pos))) 7237 { 7238 amount = -1; 7239 goto laterend; 7240 } 7241 7242 /* 7243 * #defines and so on always go at the left when included in 'cinkeys'. 7244 */ 7245 if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', TRUE))) 7246 { 7247 amount = curbuf->b_ind_hash_comment; 7248 goto theend; 7249 } 7250 7251 /* 7252 * Is it a non-case label? Then that goes at the left margin too unless: 7253 * - JS flag is set. 7254 * - 'L' item has a positive value. 7255 */ 7256 if (original_line_islabel && !curbuf->b_ind_js 7257 && curbuf->b_ind_jump_label < 0) 7258 { 7259 amount = 0; 7260 goto theend; 7261 } 7262 7263 /* 7264 * If we're inside a "//" comment and there is a "//" comment in a 7265 * previous line, lineup with that one. 7266 */ 7267 if (cin_islinecomment(theline) 7268 && (trypos = find_line_comment()) != NULL) /* XXX */ 7269 { 7270 /* find how indented the line beginning the comment is */ 7271 getvcol(curwin, trypos, &col, NULL, NULL); 7272 amount = col; 7273 goto theend; 7274 } 7275 7276 /* 7277 * If we're inside a comment and not looking at the start of the 7278 * comment, try using the 'comments' option. 7279 */ 7280 if (!cin_iscomment(theline) && comment_pos != NULL) /* XXX */ 7281 { 7282 int lead_start_len = 2; 7283 int lead_middle_len = 1; 7284 char_u lead_start[COM_MAX_LEN]; /* start-comment string */ 7285 char_u lead_middle[COM_MAX_LEN]; /* middle-comment string */ 7286 char_u lead_end[COM_MAX_LEN]; /* end-comment string */ 7287 char_u *p; 7288 int start_align = 0; 7289 int start_off = 0; 7290 int done = FALSE; 7291 7292 /* find how indented the line beginning the comment is */ 7293 getvcol(curwin, comment_pos, &col, NULL, NULL); 7294 amount = col; 7295 *lead_start = NUL; 7296 *lead_middle = NUL; 7297 7298 p = curbuf->b_p_com; 7299 while (*p != NUL) 7300 { 7301 int align = 0; 7302 int off = 0; 7303 int what = 0; 7304 7305 while (*p != NUL && *p != ':') 7306 { 7307 if (*p == COM_START || *p == COM_END || *p == COM_MIDDLE) 7308 what = *p++; 7309 else if (*p == COM_LEFT || *p == COM_RIGHT) 7310 align = *p++; 7311 else if (VIM_ISDIGIT(*p) || *p == '-') 7312 off = getdigits(&p); 7313 else 7314 ++p; 7315 } 7316 7317 if (*p == ':') 7318 ++p; 7319 (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ","); 7320 if (what == COM_START) 7321 { 7322 STRCPY(lead_start, lead_end); 7323 lead_start_len = (int)STRLEN(lead_start); 7324 start_off = off; 7325 start_align = align; 7326 } 7327 else if (what == COM_MIDDLE) 7328 { 7329 STRCPY(lead_middle, lead_end); 7330 lead_middle_len = (int)STRLEN(lead_middle); 7331 } 7332 else if (what == COM_END) 7333 { 7334 /* If our line starts with the middle comment string, line it 7335 * up with the comment opener per the 'comments' option. */ 7336 if (STRNCMP(theline, lead_middle, lead_middle_len) == 0 7337 && STRNCMP(theline, lead_end, STRLEN(lead_end)) != 0) 7338 { 7339 done = TRUE; 7340 if (curwin->w_cursor.lnum > 1) 7341 { 7342 /* If the start comment string matches in the previous 7343 * line, use the indent of that line plus offset. If 7344 * the middle comment string matches in the previous 7345 * line, use the indent of that line. XXX */ 7346 look = skipwhite(ml_get(curwin->w_cursor.lnum - 1)); 7347 if (STRNCMP(look, lead_start, lead_start_len) == 0) 7348 amount = get_indent_lnum(curwin->w_cursor.lnum - 1); 7349 else if (STRNCMP(look, lead_middle, 7350 lead_middle_len) == 0) 7351 { 7352 amount = get_indent_lnum(curwin->w_cursor.lnum - 1); 7353 break; 7354 } 7355 /* If the start comment string doesn't match with the 7356 * start of the comment, skip this entry. XXX */ 7357 else if (STRNCMP(ml_get(comment_pos->lnum) + comment_pos->col, 7358 lead_start, lead_start_len) != 0) 7359 continue; 7360 } 7361 if (start_off != 0) 7362 amount += start_off; 7363 else if (start_align == COM_RIGHT) 7364 amount += vim_strsize(lead_start) 7365 - vim_strsize(lead_middle); 7366 break; 7367 } 7368 7369 /* If our line starts with the end comment string, line it up 7370 * with the middle comment */ 7371 if (STRNCMP(theline, lead_middle, lead_middle_len) != 0 7372 && STRNCMP(theline, lead_end, STRLEN(lead_end)) == 0) 7373 { 7374 amount = get_indent_lnum(curwin->w_cursor.lnum - 1); 7375 /* XXX */ 7376 if (off != 0) 7377 amount += off; 7378 else if (align == COM_RIGHT) 7379 amount += vim_strsize(lead_start) 7380 - vim_strsize(lead_middle); 7381 done = TRUE; 7382 break; 7383 } 7384 } 7385 } 7386 7387 /* If our line starts with an asterisk, line up with the 7388 * asterisk in the comment opener; otherwise, line up 7389 * with the first character of the comment text. 7390 */ 7391 if (done) 7392 ; 7393 else if (theline[0] == '*') 7394 amount += 1; 7395 else 7396 { 7397 /* 7398 * If we are more than one line away from the comment opener, take 7399 * the indent of the previous non-empty line. If 'cino' has "CO" 7400 * and we are just below the comment opener and there are any 7401 * white characters after it line up with the text after it; 7402 * otherwise, add the amount specified by "c" in 'cino' 7403 */ 7404 amount = -1; 7405 for (lnum = cur_curpos.lnum - 1; lnum > comment_pos->lnum; --lnum) 7406 { 7407 if (linewhite(lnum)) /* skip blank lines */ 7408 continue; 7409 amount = get_indent_lnum(lnum); /* XXX */ 7410 break; 7411 } 7412 if (amount == -1) /* use the comment opener */ 7413 { 7414 if (!curbuf->b_ind_in_comment2) 7415 { 7416 start = ml_get(comment_pos->lnum); 7417 look = start + comment_pos->col + 2; /* skip / and * */ 7418 if (*look != NUL) /* if something after it */ 7419 comment_pos->col = (colnr_T)(skipwhite(look) - start); 7420 } 7421 getvcol(curwin, comment_pos, &col, NULL, NULL); 7422 amount = col; 7423 if (curbuf->b_ind_in_comment2 || *look == NUL) 7424 amount += curbuf->b_ind_in_comment; 7425 } 7426 } 7427 goto theend; 7428 } 7429 7430 /* 7431 * Are we looking at a ']' that has a match? 7432 */ 7433 if (*skipwhite(theline) == ']' 7434 && (trypos = find_match_char('[', curbuf->b_ind_maxparen)) != NULL) 7435 { 7436 /* align with the line containing the '['. */ 7437 amount = get_indent_lnum(trypos->lnum); 7438 goto theend; 7439 } 7440 7441 /* 7442 * Are we inside parentheses or braces? 7443 */ /* XXX */ 7444 if (((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL 7445 && curbuf->b_ind_java == 0) 7446 || (tryposBrace = find_start_brace()) != NULL 7447 || trypos != NULL) 7448 { 7449 if (trypos != NULL && tryposBrace != NULL) 7450 { 7451 /* Both an unmatched '(' and '{' is found. Use the one which is 7452 * closer to the current cursor position, set the other to NULL. */ 7453 if (trypos->lnum != tryposBrace->lnum 7454 ? trypos->lnum < tryposBrace->lnum 7455 : trypos->col < tryposBrace->col) 7456 trypos = NULL; 7457 else 7458 tryposBrace = NULL; 7459 } 7460 7461 if (trypos != NULL) 7462 { 7463 /* 7464 * If the matching paren is more than one line away, use the indent of 7465 * a previous non-empty line that matches the same paren. 7466 */ 7467 if (theline[0] == ')' && curbuf->b_ind_paren_prev) 7468 { 7469 /* Line up with the start of the matching paren line. */ 7470 amount = get_indent_lnum(curwin->w_cursor.lnum - 1); /* XXX */ 7471 } 7472 else 7473 { 7474 amount = -1; 7475 our_paren_pos = *trypos; 7476 for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum) 7477 { 7478 l = skipwhite(ml_get(lnum)); 7479 if (cin_nocode(l)) /* skip comment lines */ 7480 continue; 7481 if (cin_ispreproc_cont(&l, &lnum, &amount)) 7482 continue; /* ignore #define, #if, etc. */ 7483 curwin->w_cursor.lnum = lnum; 7484 7485 /* Skip a comment or raw string. XXX */ 7486 if ((trypos = ind_find_start_CORS()) != NULL) 7487 { 7488 lnum = trypos->lnum + 1; 7489 continue; 7490 } 7491 7492 /* XXX */ 7493 if ((trypos = find_match_paren( 7494 corr_ind_maxparen(&cur_curpos))) != NULL 7495 && trypos->lnum == our_paren_pos.lnum 7496 && trypos->col == our_paren_pos.col) 7497 { 7498 amount = get_indent_lnum(lnum); /* XXX */ 7499 7500 if (theline[0] == ')') 7501 { 7502 if (our_paren_pos.lnum != lnum 7503 && cur_amount > amount) 7504 cur_amount = amount; 7505 amount = -1; 7506 } 7507 break; 7508 } 7509 } 7510 } 7511 7512 /* 7513 * Line up with line where the matching paren is. XXX 7514 * If the line starts with a '(' or the indent for unclosed 7515 * parentheses is zero, line up with the unclosed parentheses. 7516 */ 7517 if (amount == -1) 7518 { 7519 int ignore_paren_col = 0; 7520 int is_if_for_while = 0; 7521 7522 if (curbuf->b_ind_if_for_while) 7523 { 7524 /* Look for the outermost opening parenthesis on this line 7525 * and check whether it belongs to an "if", "for" or "while". */ 7526 7527 pos_T cursor_save = curwin->w_cursor; 7528 pos_T outermost; 7529 char_u *line; 7530 7531 trypos = &our_paren_pos; 7532 do { 7533 outermost = *trypos; 7534 curwin->w_cursor.lnum = outermost.lnum; 7535 curwin->w_cursor.col = outermost.col; 7536 7537 trypos = find_match_paren(curbuf->b_ind_maxparen); 7538 } while (trypos && trypos->lnum == outermost.lnum); 7539 7540 curwin->w_cursor = cursor_save; 7541 7542 line = ml_get(outermost.lnum); 7543 7544 is_if_for_while = 7545 cin_is_if_for_while_before_offset(line, &outermost.col); 7546 } 7547 7548 amount = skip_label(our_paren_pos.lnum, &look); 7549 look = skipwhite(look); 7550 if (*look == '(') 7551 { 7552 linenr_T save_lnum = curwin->w_cursor.lnum; 7553 char_u *line; 7554 int look_col; 7555 7556 /* Ignore a '(' in front of the line that has a match before 7557 * our matching '('. */ 7558 curwin->w_cursor.lnum = our_paren_pos.lnum; 7559 line = ml_get_curline(); 7560 look_col = (int)(look - line); 7561 curwin->w_cursor.col = look_col + 1; 7562 if ((trypos = findmatchlimit(NULL, ')', 0, 7563 curbuf->b_ind_maxparen)) 7564 != NULL 7565 && trypos->lnum == our_paren_pos.lnum 7566 && trypos->col < our_paren_pos.col) 7567 ignore_paren_col = trypos->col + 1; 7568 7569 curwin->w_cursor.lnum = save_lnum; 7570 look = ml_get(our_paren_pos.lnum) + look_col; 7571 } 7572 if (theline[0] == ')' || (curbuf->b_ind_unclosed == 0 7573 && is_if_for_while == 0) 7574 || (!curbuf->b_ind_unclosed_noignore && *look == '(' 7575 && ignore_paren_col == 0)) 7576 { 7577 /* 7578 * If we're looking at a close paren, line up right there; 7579 * otherwise, line up with the next (non-white) character. 7580 * When b_ind_unclosed_wrapped is set and the matching paren is 7581 * the last nonwhite character of the line, use either the 7582 * indent of the current line or the indentation of the next 7583 * outer paren and add b_ind_unclosed_wrapped (for very long 7584 * lines). 7585 */ 7586 if (theline[0] != ')') 7587 { 7588 cur_amount = MAXCOL; 7589 l = ml_get(our_paren_pos.lnum); 7590 if (curbuf->b_ind_unclosed_wrapped 7591 && cin_ends_in(l, (char_u *)"(", NULL)) 7592 { 7593 /* look for opening unmatched paren, indent one level 7594 * for each additional level */ 7595 n = 1; 7596 for (col = 0; col < our_paren_pos.col; ++col) 7597 { 7598 switch (l[col]) 7599 { 7600 case '(': 7601 case '{': ++n; 7602 break; 7603 7604 case ')': 7605 case '}': if (n > 1) 7606 --n; 7607 break; 7608 } 7609 } 7610 7611 our_paren_pos.col = 0; 7612 amount += n * curbuf->b_ind_unclosed_wrapped; 7613 } 7614 else if (curbuf->b_ind_unclosed_whiteok) 7615 our_paren_pos.col++; 7616 else 7617 { 7618 col = our_paren_pos.col + 1; 7619 while (VIM_ISWHITE(l[col])) 7620 col++; 7621 if (l[col] != NUL) /* In case of trailing space */ 7622 our_paren_pos.col = col; 7623 else 7624 our_paren_pos.col++; 7625 } 7626 } 7627 7628 /* 7629 * Find how indented the paren is, or the character after it 7630 * if we did the above "if". 7631 */ 7632 if (our_paren_pos.col > 0) 7633 { 7634 getvcol(curwin, &our_paren_pos, &col, NULL, NULL); 7635 if (cur_amount > (int)col) 7636 cur_amount = col; 7637 } 7638 } 7639 7640 if (theline[0] == ')' && curbuf->b_ind_matching_paren) 7641 { 7642 /* Line up with the start of the matching paren line. */ 7643 } 7644 else if ((curbuf->b_ind_unclosed == 0 && is_if_for_while == 0) 7645 || (!curbuf->b_ind_unclosed_noignore 7646 && *look == '(' && ignore_paren_col == 0)) 7647 { 7648 if (cur_amount != MAXCOL) 7649 amount = cur_amount; 7650 } 7651 else 7652 { 7653 /* Add b_ind_unclosed2 for each '(' before our matching one, 7654 * but ignore (void) before the line (ignore_paren_col). */ 7655 col = our_paren_pos.col; 7656 while ((int)our_paren_pos.col > ignore_paren_col) 7657 { 7658 --our_paren_pos.col; 7659 switch (*ml_get_pos(&our_paren_pos)) 7660 { 7661 case '(': amount += curbuf->b_ind_unclosed2; 7662 col = our_paren_pos.col; 7663 break; 7664 case ')': amount -= curbuf->b_ind_unclosed2; 7665 col = MAXCOL; 7666 break; 7667 } 7668 } 7669 7670 /* Use b_ind_unclosed once, when the first '(' is not inside 7671 * braces */ 7672 if (col == MAXCOL) 7673 amount += curbuf->b_ind_unclosed; 7674 else 7675 { 7676 curwin->w_cursor.lnum = our_paren_pos.lnum; 7677 curwin->w_cursor.col = col; 7678 if (find_match_paren_after_brace(curbuf->b_ind_maxparen) 7679 != NULL) 7680 amount += curbuf->b_ind_unclosed2; 7681 else 7682 { 7683 if (is_if_for_while) 7684 amount += curbuf->b_ind_if_for_while; 7685 else 7686 amount += curbuf->b_ind_unclosed; 7687 } 7688 } 7689 /* 7690 * For a line starting with ')' use the minimum of the two 7691 * positions, to avoid giving it more indent than the previous 7692 * lines: 7693 * func_long_name( if (x 7694 * arg && yy 7695 * ) ^ not here ) ^ not here 7696 */ 7697 if (cur_amount < amount) 7698 amount = cur_amount; 7699 } 7700 } 7701 7702 /* add extra indent for a comment */ 7703 if (cin_iscomment(theline)) 7704 amount += curbuf->b_ind_comment; 7705 } 7706 else 7707 { 7708 /* 7709 * We are inside braces, there is a { before this line at the position 7710 * stored in tryposBrace. 7711 * Make a copy of tryposBrace, it may point to pos_copy inside 7712 * find_start_brace(), which may be changed somewhere. 7713 */ 7714 tryposCopy = *tryposBrace; 7715 tryposBrace = &tryposCopy; 7716 trypos = tryposBrace; 7717 ourscope = trypos->lnum; 7718 start = ml_get(ourscope); 7719 7720 /* 7721 * Now figure out how indented the line is in general. 7722 * If the brace was at the start of the line, we use that; 7723 * otherwise, check out the indentation of the line as 7724 * a whole and then add the "imaginary indent" to that. 7725 */ 7726 look = skipwhite(start); 7727 if (*look == '{') 7728 { 7729 getvcol(curwin, trypos, &col, NULL, NULL); 7730 amount = col; 7731 if (*start == '{') 7732 start_brace = BRACE_IN_COL0; 7733 else 7734 start_brace = BRACE_AT_START; 7735 } 7736 else 7737 { 7738 /* That opening brace might have been on a continuation 7739 * line. if so, find the start of the line. */ 7740 curwin->w_cursor.lnum = ourscope; 7741 7742 /* Position the cursor over the rightmost paren, so that 7743 * matching it will take us back to the start of the line. */ 7744 lnum = ourscope; 7745 if (find_last_paren(start, '(', ')') 7746 && (trypos = find_match_paren(curbuf->b_ind_maxparen)) 7747 != NULL) 7748 lnum = trypos->lnum; 7749 7750 /* It could have been something like 7751 * case 1: if (asdf && 7752 * ldfd) { 7753 * } 7754 */ 7755 if ((curbuf->b_ind_js || curbuf->b_ind_keep_case_label) 7756 && cin_iscase(skipwhite(ml_get_curline()), FALSE)) 7757 amount = get_indent(); 7758 else if (curbuf->b_ind_js) 7759 amount = get_indent_lnum(lnum); 7760 else 7761 amount = skip_label(lnum, &l); 7762 7763 start_brace = BRACE_AT_END; 7764 } 7765 7766 /* For Javascript check if the line starts with "key:". */ 7767 if (curbuf->b_ind_js) 7768 js_cur_has_key = cin_has_js_key(theline); 7769 7770 /* 7771 * If we're looking at a closing brace, that's where 7772 * we want to be. otherwise, add the amount of room 7773 * that an indent is supposed to be. 7774 */ 7775 if (theline[0] == '}') 7776 { 7777 /* 7778 * they may want closing braces to line up with something 7779 * other than the open brace. indulge them, if so. 7780 */ 7781 amount += curbuf->b_ind_close_extra; 7782 } 7783 else 7784 { 7785 /* 7786 * If we're looking at an "else", try to find an "if" 7787 * to match it with. 7788 * If we're looking at a "while", try to find a "do" 7789 * to match it with. 7790 */ 7791 lookfor = LOOKFOR_INITIAL; 7792 if (cin_iselse(theline)) 7793 lookfor = LOOKFOR_IF; 7794 else if (cin_iswhileofdo(theline, cur_curpos.lnum)) /* XXX */ 7795 lookfor = LOOKFOR_DO; 7796 if (lookfor != LOOKFOR_INITIAL) 7797 { 7798 curwin->w_cursor.lnum = cur_curpos.lnum; 7799 if (find_match(lookfor, ourscope) == OK) 7800 { 7801 amount = get_indent(); /* XXX */ 7802 goto theend; 7803 } 7804 } 7805 7806 /* 7807 * We get here if we are not on an "while-of-do" or "else" (or 7808 * failed to find a matching "if"). 7809 * Search backwards for something to line up with. 7810 * First set amount for when we don't find anything. 7811 */ 7812 7813 /* 7814 * if the '{' is _really_ at the left margin, use the imaginary 7815 * location of a left-margin brace. Otherwise, correct the 7816 * location for b_ind_open_extra. 7817 */ 7818 7819 if (start_brace == BRACE_IN_COL0) /* '{' is in column 0 */ 7820 { 7821 amount = curbuf->b_ind_open_left_imag; 7822 lookfor_cpp_namespace = TRUE; 7823 } 7824 else if (start_brace == BRACE_AT_START && 7825 lookfor_cpp_namespace) /* '{' is at start */ 7826 { 7827 7828 lookfor_cpp_namespace = TRUE; 7829 } 7830 else 7831 { 7832 if (start_brace == BRACE_AT_END) /* '{' is at end of line */ 7833 { 7834 amount += curbuf->b_ind_open_imag; 7835 7836 l = skipwhite(ml_get_curline()); 7837 if (cin_is_cpp_namespace(l)) 7838 amount += curbuf->b_ind_cpp_namespace; 7839 else if (cin_is_cpp_extern_c(l)) 7840 amount += curbuf->b_ind_cpp_extern_c; 7841 } 7842 else 7843 { 7844 /* Compensate for adding b_ind_open_extra later. */ 7845 amount -= curbuf->b_ind_open_extra; 7846 if (amount < 0) 7847 amount = 0; 7848 } 7849 } 7850 7851 lookfor_break = FALSE; 7852 7853 if (cin_iscase(theline, FALSE)) /* it's a switch() label */ 7854 { 7855 lookfor = LOOKFOR_CASE; /* find a previous switch() label */ 7856 amount += curbuf->b_ind_case; 7857 } 7858 else if (cin_isscopedecl(theline)) /* private:, ... */ 7859 { 7860 lookfor = LOOKFOR_SCOPEDECL; /* class decl is this block */ 7861 amount += curbuf->b_ind_scopedecl; 7862 } 7863 else 7864 { 7865 if (curbuf->b_ind_case_break && cin_isbreak(theline)) 7866 /* break; ... */ 7867 lookfor_break = TRUE; 7868 7869 lookfor = LOOKFOR_INITIAL; 7870 /* b_ind_level from start of block */ 7871 amount += curbuf->b_ind_level; 7872 } 7873 scope_amount = amount; 7874 whilelevel = 0; 7875 7876 /* 7877 * Search backwards. If we find something we recognize, line up 7878 * with that. 7879 * 7880 * If we're looking at an open brace, indent 7881 * the usual amount relative to the conditional 7882 * that opens the block. 7883 */ 7884 curwin->w_cursor = cur_curpos; 7885 for (;;) 7886 { 7887 curwin->w_cursor.lnum--; 7888 curwin->w_cursor.col = 0; 7889 7890 /* 7891 * If we went all the way back to the start of our scope, line 7892 * up with it. 7893 */ 7894 if (curwin->w_cursor.lnum <= ourscope) 7895 { 7896 /* We reached end of scope: 7897 * If looking for a enum or structure initialization 7898 * go further back: 7899 * If it is an initializer (enum xxx or xxx =), then 7900 * don't add ind_continuation, otherwise it is a variable 7901 * declaration: 7902 * int x, 7903 * here; <-- add ind_continuation 7904 */ 7905 if (lookfor == LOOKFOR_ENUM_OR_INIT) 7906 { 7907 if (curwin->w_cursor.lnum == 0 7908 || curwin->w_cursor.lnum 7909 < ourscope - curbuf->b_ind_maxparen) 7910 { 7911 /* nothing found (abuse curbuf->b_ind_maxparen as 7912 * limit) assume terminated line (i.e. a variable 7913 * initialization) */ 7914 if (cont_amount > 0) 7915 amount = cont_amount; 7916 else if (!curbuf->b_ind_js) 7917 amount += ind_continuation; 7918 break; 7919 } 7920 7921 l = ml_get_curline(); 7922 7923 /* 7924 * If we're in a comment or raw string now, skip to 7925 * the start of it. 7926 */ 7927 trypos = ind_find_start_CORS(); 7928 if (trypos != NULL) 7929 { 7930 curwin->w_cursor.lnum = trypos->lnum + 1; 7931 curwin->w_cursor.col = 0; 7932 continue; 7933 } 7934 7935 /* 7936 * Skip preprocessor directives and blank lines. 7937 */ 7938 if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, 7939 &amount)) 7940 continue; 7941 7942 if (cin_nocode(l)) 7943 continue; 7944 7945 terminated = cin_isterminated(l, FALSE, TRUE); 7946 7947 /* 7948 * If we are at top level and the line looks like a 7949 * function declaration, we are done 7950 * (it's a variable declaration). 7951 */ 7952 if (start_brace != BRACE_IN_COL0 7953 || !cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0)) 7954 { 7955 /* if the line is terminated with another ',' 7956 * it is a continued variable initialization. 7957 * don't add extra indent. 7958 * TODO: does not work, if a function 7959 * declaration is split over multiple lines: 7960 * cin_isfuncdecl returns FALSE then. 7961 */ 7962 if (terminated == ',') 7963 break; 7964 7965 /* if it es a enum declaration or an assignment, 7966 * we are done. 7967 */ 7968 if (terminated != ';' && cin_isinit()) 7969 break; 7970 7971 /* nothing useful found */ 7972 if (terminated == 0 || terminated == '{') 7973 continue; 7974 } 7975 7976 if (terminated != ';') 7977 { 7978 /* Skip parens and braces. Position the cursor 7979 * over the rightmost paren, so that matching it 7980 * will take us back to the start of the line. 7981 */ /* XXX */ 7982 trypos = NULL; 7983 if (find_last_paren(l, '(', ')')) 7984 trypos = find_match_paren( 7985 curbuf->b_ind_maxparen); 7986 7987 if (trypos == NULL && find_last_paren(l, '{', '}')) 7988 trypos = find_start_brace(); 7989 7990 if (trypos != NULL) 7991 { 7992 curwin->w_cursor.lnum = trypos->lnum + 1; 7993 curwin->w_cursor.col = 0; 7994 continue; 7995 } 7996 } 7997 7998 /* it's a variable declaration, add indentation 7999 * like in 8000 * int a, 8001 * b; 8002 */ 8003 if (cont_amount > 0) 8004 amount = cont_amount; 8005 else 8006 amount += ind_continuation; 8007 } 8008 else if (lookfor == LOOKFOR_UNTERM) 8009 { 8010 if (cont_amount > 0) 8011 amount = cont_amount; 8012 else 8013 amount += ind_continuation; 8014 } 8015 else 8016 { 8017 if (lookfor != LOOKFOR_TERM 8018 && lookfor != LOOKFOR_CPP_BASECLASS 8019 && lookfor != LOOKFOR_COMMA) 8020 { 8021 amount = scope_amount; 8022 if (theline[0] == '{') 8023 { 8024 amount += curbuf->b_ind_open_extra; 8025 added_to_amount = curbuf->b_ind_open_extra; 8026 } 8027 } 8028 8029 if (lookfor_cpp_namespace) 8030 { 8031 /* 8032 * Looking for C++ namespace, need to look further 8033 * back. 8034 */ 8035 if (curwin->w_cursor.lnum == ourscope) 8036 continue; 8037 8038 if (curwin->w_cursor.lnum == 0 8039 || curwin->w_cursor.lnum 8040 < ourscope - FIND_NAMESPACE_LIM) 8041 break; 8042 8043 l = ml_get_curline(); 8044 8045 /* If we're in a comment or raw string now, skip 8046 * to the start of it. */ 8047 trypos = ind_find_start_CORS(); 8048 if (trypos != NULL) 8049 { 8050 curwin->w_cursor.lnum = trypos->lnum + 1; 8051 curwin->w_cursor.col = 0; 8052 continue; 8053 } 8054 8055 /* Skip preprocessor directives and blank lines. */ 8056 if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, 8057 &amount)) 8058 continue; 8059 8060 /* Finally the actual check for "namespace". */ 8061 if (cin_is_cpp_namespace(l)) 8062 { 8063 amount += curbuf->b_ind_cpp_namespace 8064 - added_to_amount; 8065 break; 8066 } 8067 else if (cin_is_cpp_extern_c(l)) 8068 { 8069 amount += curbuf->b_ind_cpp_extern_c 8070 - added_to_amount; 8071 break; 8072 } 8073 8074 if (cin_nocode(l)) 8075 continue; 8076 } 8077 } 8078 break; 8079 } 8080 8081 /* 8082 * If we're in a comment or raw string now, skip to the start 8083 * of it. 8084 */ /* XXX */ 8085 if ((trypos = ind_find_start_CORS()) != NULL) 8086 { 8087 curwin->w_cursor.lnum = trypos->lnum + 1; 8088 curwin->w_cursor.col = 0; 8089 continue; 8090 } 8091 8092 l = ml_get_curline(); 8093 8094 /* 8095 * If this is a switch() label, may line up relative to that. 8096 * If this is a C++ scope declaration, do the same. 8097 */ 8098 iscase = cin_iscase(l, FALSE); 8099 if (iscase || cin_isscopedecl(l)) 8100 { 8101 /* we are only looking for cpp base class 8102 * declaration/initialization any longer */ 8103 if (lookfor == LOOKFOR_CPP_BASECLASS) 8104 break; 8105 8106 /* When looking for a "do" we are not interested in 8107 * labels. */ 8108 if (whilelevel > 0) 8109 continue; 8110 8111 /* 8112 * case xx: 8113 * c = 99 + <- this indent plus continuation 8114 *-> here; 8115 */ 8116 if (lookfor == LOOKFOR_UNTERM 8117 || lookfor == LOOKFOR_ENUM_OR_INIT) 8118 { 8119 if (cont_amount > 0) 8120 amount = cont_amount; 8121 else 8122 amount += ind_continuation; 8123 break; 8124 } 8125 8126 /* 8127 * case xx: <- line up with this case 8128 * x = 333; 8129 * case yy: 8130 */ 8131 if ( (iscase && lookfor == LOOKFOR_CASE) 8132 || (iscase && lookfor_break) 8133 || (!iscase && lookfor == LOOKFOR_SCOPEDECL)) 8134 { 8135 /* 8136 * Check that this case label is not for another 8137 * switch() 8138 */ /* XXX */ 8139 if ((trypos = find_start_brace()) == NULL 8140 || trypos->lnum == ourscope) 8141 { 8142 amount = get_indent(); /* XXX */ 8143 break; 8144 } 8145 continue; 8146 } 8147 8148 n = get_indent_nolabel(curwin->w_cursor.lnum); /* XXX */ 8149 8150 /* 8151 * case xx: if (cond) <- line up with this if 8152 * y = y + 1; 8153 * -> s = 99; 8154 * 8155 * case xx: 8156 * if (cond) <- line up with this line 8157 * y = y + 1; 8158 * -> s = 99; 8159 */ 8160 if (lookfor == LOOKFOR_TERM) 8161 { 8162 if (n) 8163 amount = n; 8164 8165 if (!lookfor_break) 8166 break; 8167 } 8168 8169 /* 8170 * case xx: x = x + 1; <- line up with this x 8171 * -> y = y + 1; 8172 * 8173 * case xx: if (cond) <- line up with this if 8174 * -> y = y + 1; 8175 */ 8176 if (n) 8177 { 8178 amount = n; 8179 l = after_label(ml_get_curline()); 8180 if (l != NULL && cin_is_cinword(l)) 8181 { 8182 if (theline[0] == '{') 8183 amount += curbuf->b_ind_open_extra; 8184 else 8185 amount += curbuf->b_ind_level 8186 + curbuf->b_ind_no_brace; 8187 } 8188 break; 8189 } 8190 8191 /* 8192 * Try to get the indent of a statement before the switch 8193 * label. If nothing is found, line up relative to the 8194 * switch label. 8195 * break; <- may line up with this line 8196 * case xx: 8197 * -> y = 1; 8198 */ 8199 scope_amount = get_indent() + (iscase /* XXX */ 8200 ? curbuf->b_ind_case_code 8201 : curbuf->b_ind_scopedecl_code); 8202 lookfor = curbuf->b_ind_case_break 8203 ? LOOKFOR_NOBREAK : LOOKFOR_ANY; 8204 continue; 8205 } 8206 8207 /* 8208 * Looking for a switch() label or C++ scope declaration, 8209 * ignore other lines, skip {}-blocks. 8210 */ 8211 if (lookfor == LOOKFOR_CASE || lookfor == LOOKFOR_SCOPEDECL) 8212 { 8213 if (find_last_paren(l, '{', '}') 8214 && (trypos = find_start_brace()) != NULL) 8215 { 8216 curwin->w_cursor.lnum = trypos->lnum + 1; 8217 curwin->w_cursor.col = 0; 8218 } 8219 continue; 8220 } 8221 8222 /* 8223 * Ignore jump labels with nothing after them. 8224 */ 8225 if (!curbuf->b_ind_js && cin_islabel()) 8226 { 8227 l = after_label(ml_get_curline()); 8228 if (l == NULL || cin_nocode(l)) 8229 continue; 8230 } 8231 8232 /* 8233 * Ignore #defines, #if, etc. 8234 * Ignore comment and empty lines. 8235 * (need to get the line again, cin_islabel() may have 8236 * unlocked it) 8237 */ 8238 l = ml_get_curline(); 8239 if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount) 8240 || cin_nocode(l)) 8241 continue; 8242 8243 /* 8244 * Are we at the start of a cpp base class declaration or 8245 * constructor initialization? 8246 */ /* XXX */ 8247 n = FALSE; 8248 if (lookfor != LOOKFOR_TERM && curbuf->b_ind_cpp_baseclass > 0) 8249 { 8250 n = cin_is_cpp_baseclass(&cache_cpp_baseclass); 8251 l = ml_get_curline(); 8252 } 8253 if (n) 8254 { 8255 if (lookfor == LOOKFOR_UNTERM) 8256 { 8257 if (cont_amount > 0) 8258 amount = cont_amount; 8259 else 8260 amount += ind_continuation; 8261 } 8262 else if (theline[0] == '{') 8263 { 8264 /* Need to find start of the declaration. */ 8265 lookfor = LOOKFOR_UNTERM; 8266 ind_continuation = 0; 8267 continue; 8268 } 8269 else 8270 /* XXX */ 8271 amount = get_baseclass_amount( 8272 cache_cpp_baseclass.lpos.col); 8273 break; 8274 } 8275 else if (lookfor == LOOKFOR_CPP_BASECLASS) 8276 { 8277 /* only look, whether there is a cpp base class 8278 * declaration or initialization before the opening brace. 8279 */ 8280 if (cin_isterminated(l, TRUE, FALSE)) 8281 break; 8282 else 8283 continue; 8284 } 8285 8286 /* 8287 * What happens next depends on the line being terminated. 8288 * If terminated with a ',' only consider it terminating if 8289 * there is another unterminated statement behind, eg: 8290 * 123, 8291 * sizeof 8292 * here 8293 * Otherwise check whether it is a enumeration or structure 8294 * initialisation (not indented) or a variable declaration 8295 * (indented). 8296 */ 8297 terminated = cin_isterminated(l, FALSE, TRUE); 8298 8299 if (js_cur_has_key) 8300 { 8301 js_cur_has_key = 0; /* only check the first line */ 8302 if (curbuf->b_ind_js && terminated == ',') 8303 { 8304 /* For Javascript we might be inside an object: 8305 * key: something, <- align with this 8306 * key: something 8307 * or: 8308 * key: something + <- align with this 8309 * something, 8310 * key: something 8311 */ 8312 lookfor = LOOKFOR_JS_KEY; 8313 } 8314 } 8315 if (lookfor == LOOKFOR_JS_KEY && cin_has_js_key(l)) 8316 { 8317 amount = get_indent(); 8318 break; 8319 } 8320 if (lookfor == LOOKFOR_COMMA) 8321 { 8322 if (tryposBrace != NULL && tryposBrace->lnum 8323 >= curwin->w_cursor.lnum) 8324 break; 8325 if (terminated == ',') 8326 /* line below current line is the one that starts a 8327 * (possibly broken) line ending in a comma. */ 8328 break; 8329 else 8330 { 8331 amount = get_indent(); 8332 if (curwin->w_cursor.lnum - 1 == ourscope) 8333 /* line above is start of the scope, thus current 8334 * line is the one that stars a (possibly broken) 8335 * line ending in a comma. */ 8336 break; 8337 } 8338 } 8339 8340 if (terminated == 0 || (lookfor != LOOKFOR_UNTERM 8341 && terminated == ',')) 8342 { 8343 if (lookfor != LOOKFOR_ENUM_OR_INIT && 8344 (*skipwhite(l) == '[' || l[STRLEN(l) - 1] == '[')) 8345 amount += ind_continuation; 8346 /* 8347 * if we're in the middle of a paren thing, 8348 * go back to the line that starts it so 8349 * we can get the right prevailing indent 8350 * if ( foo && 8351 * bar ) 8352 */ 8353 /* 8354 * Position the cursor over the rightmost paren, so that 8355 * matching it will take us back to the start of the line. 8356 * Ignore a match before the start of the block. 8357 */ 8358 (void)find_last_paren(l, '(', ')'); 8359 trypos = find_match_paren(corr_ind_maxparen(&cur_curpos)); 8360 if (trypos != NULL && (trypos->lnum < tryposBrace->lnum 8361 || (trypos->lnum == tryposBrace->lnum 8362 && trypos->col < tryposBrace->col))) 8363 trypos = NULL; 8364 8365 /* 8366 * If we are looking for ',', we also look for matching 8367 * braces. 8368 */ 8369 if (trypos == NULL && terminated == ',' 8370 && find_last_paren(l, '{', '}')) 8371 trypos = find_start_brace(); 8372 8373 if (trypos != NULL) 8374 { 8375 /* 8376 * Check if we are on a case label now. This is 8377 * handled above. 8378 * case xx: if ( asdf && 8379 * asdf) 8380 */ 8381 curwin->w_cursor = *trypos; 8382 l = ml_get_curline(); 8383 if (cin_iscase(l, FALSE) || cin_isscopedecl(l)) 8384 { 8385 ++curwin->w_cursor.lnum; 8386 curwin->w_cursor.col = 0; 8387 continue; 8388 } 8389 } 8390 8391 /* 8392 * Skip over continuation lines to find the one to get the 8393 * indent from 8394 * char *usethis = "bla\ 8395 * bla", 8396 * here; 8397 */ 8398 if (terminated == ',') 8399 { 8400 while (curwin->w_cursor.lnum > 1) 8401 { 8402 l = ml_get(curwin->w_cursor.lnum - 1); 8403 if (*l == NUL || l[STRLEN(l) - 1] != '\\') 8404 break; 8405 --curwin->w_cursor.lnum; 8406 curwin->w_cursor.col = 0; 8407 } 8408 } 8409 8410 /* 8411 * Get indent and pointer to text for current line, 8412 * ignoring any jump label. XXX 8413 */ 8414 if (curbuf->b_ind_js) 8415 cur_amount = get_indent(); 8416 else 8417 cur_amount = skip_label(curwin->w_cursor.lnum, &l); 8418 /* 8419 * If this is just above the line we are indenting, and it 8420 * starts with a '{', line it up with this line. 8421 * while (not) 8422 * -> { 8423 * } 8424 */ 8425 if (terminated != ',' && lookfor != LOOKFOR_TERM 8426 && theline[0] == '{') 8427 { 8428 amount = cur_amount; 8429 /* 8430 * Only add b_ind_open_extra when the current line 8431 * doesn't start with a '{', which must have a match 8432 * in the same line (scope is the same). Probably: 8433 * { 1, 2 }, 8434 * -> { 3, 4 } 8435 */ 8436 if (*skipwhite(l) != '{') 8437 amount += curbuf->b_ind_open_extra; 8438 8439 if (curbuf->b_ind_cpp_baseclass && !curbuf->b_ind_js) 8440 { 8441 /* have to look back, whether it is a cpp base 8442 * class declaration or initialization */ 8443 lookfor = LOOKFOR_CPP_BASECLASS; 8444 continue; 8445 } 8446 break; 8447 } 8448 8449 /* 8450 * Check if we are after an "if", "while", etc. 8451 * Also allow " } else". 8452 */ 8453 if (cin_is_cinword(l) || cin_iselse(skipwhite(l))) 8454 { 8455 /* 8456 * Found an unterminated line after an if (), line up 8457 * with the last one. 8458 * if (cond) 8459 * 100 + 8460 * -> here; 8461 */ 8462 if (lookfor == LOOKFOR_UNTERM 8463 || lookfor == LOOKFOR_ENUM_OR_INIT) 8464 { 8465 if (cont_amount > 0) 8466 amount = cont_amount; 8467 else 8468 amount += ind_continuation; 8469 break; 8470 } 8471 8472 /* 8473 * If this is just above the line we are indenting, we 8474 * are finished. 8475 * while (not) 8476 * -> here; 8477 * Otherwise this indent can be used when the line 8478 * before this is terminated. 8479 * yyy; 8480 * if (stat) 8481 * while (not) 8482 * xxx; 8483 * -> here; 8484 */ 8485 amount = cur_amount; 8486 if (theline[0] == '{') 8487 amount += curbuf->b_ind_open_extra; 8488 if (lookfor != LOOKFOR_TERM) 8489 { 8490 amount += curbuf->b_ind_level 8491 + curbuf->b_ind_no_brace; 8492 break; 8493 } 8494 8495 /* 8496 * Special trick: when expecting the while () after a 8497 * do, line up with the while() 8498 * do 8499 * x = 1; 8500 * -> here 8501 */ 8502 l = skipwhite(ml_get_curline()); 8503 if (cin_isdo(l)) 8504 { 8505 if (whilelevel == 0) 8506 break; 8507 --whilelevel; 8508 } 8509 8510 /* 8511 * When searching for a terminated line, don't use the 8512 * one between the "if" and the matching "else". 8513 * Need to use the scope of this "else". XXX 8514 * If whilelevel != 0 continue looking for a "do {". 8515 */ 8516 if (cin_iselse(l) && whilelevel == 0) 8517 { 8518 /* If we're looking at "} else", let's make sure we 8519 * find the opening brace of the enclosing scope, 8520 * not the one from "if () {". */ 8521 if (*l == '}') 8522 curwin->w_cursor.col = 8523 (colnr_T)(l - ml_get_curline()) + 1; 8524 8525 if ((trypos = find_start_brace()) == NULL 8526 || find_match(LOOKFOR_IF, trypos->lnum) 8527 == FAIL) 8528 break; 8529 } 8530 } 8531 8532 /* 8533 * If we're below an unterminated line that is not an 8534 * "if" or something, we may line up with this line or 8535 * add something for a continuation line, depending on 8536 * the line before this one. 8537 */ 8538 else 8539 { 8540 /* 8541 * Found two unterminated lines on a row, line up with 8542 * the last one. 8543 * c = 99 + 8544 * 100 + 8545 * -> here; 8546 */ 8547 if (lookfor == LOOKFOR_UNTERM) 8548 { 8549 /* When line ends in a comma add extra indent */ 8550 if (terminated == ',') 8551 amount += ind_continuation; 8552 break; 8553 } 8554 8555 if (lookfor == LOOKFOR_ENUM_OR_INIT) 8556 { 8557 /* Found two lines ending in ',', lineup with the 8558 * lowest one, but check for cpp base class 8559 * declaration/initialization, if it is an 8560 * opening brace or we are looking just for 8561 * enumerations/initializations. */ 8562 if (terminated == ',') 8563 { 8564 if (curbuf->b_ind_cpp_baseclass == 0) 8565 break; 8566 8567 lookfor = LOOKFOR_CPP_BASECLASS; 8568 continue; 8569 } 8570 8571 /* Ignore unterminated lines in between, but 8572 * reduce indent. */ 8573 if (amount > cur_amount) 8574 amount = cur_amount; 8575 } 8576 else 8577 { 8578 /* 8579 * Found first unterminated line on a row, may 8580 * line up with this line, remember its indent 8581 * 100 + 8582 * -> here; 8583 */ 8584 l = ml_get_curline(); 8585 amount = cur_amount; 8586 8587 n = (int)STRLEN(l); 8588 if (terminated == ',' && (*skipwhite(l) == ']' 8589 || (n >=2 && l[n - 2] == ']'))) 8590 break; 8591 8592 /* 8593 * If previous line ends in ',', check whether we 8594 * are in an initialization or enum 8595 * struct xxx = 8596 * { 8597 * sizeof a, 8598 * 124 }; 8599 * or a normal possible continuation line. 8600 * but only, of no other statement has been found 8601 * yet. 8602 */ 8603 if (lookfor == LOOKFOR_INITIAL && terminated == ',') 8604 { 8605 if (curbuf->b_ind_js) 8606 { 8607 /* Search for a line ending in a comma 8608 * and line up with the line below it 8609 * (could be the current line). 8610 * some = [ 8611 * 1, <- line up here 8612 * 2, 8613 * some = [ 8614 * 3 + <- line up here 8615 * 4 * 8616 * 5, 8617 * 6, 8618 */ 8619 if (cin_iscomment(skipwhite(l))) 8620 break; 8621 lookfor = LOOKFOR_COMMA; 8622 trypos = find_match_char('[', 8623 curbuf->b_ind_maxparen); 8624 if (trypos != NULL) 8625 { 8626 if (trypos->lnum 8627 == curwin->w_cursor.lnum - 1) 8628 { 8629 /* Current line is first inside 8630 * [], line up with it. */ 8631 break; 8632 } 8633 ourscope = trypos->lnum; 8634 } 8635 } 8636 else 8637 { 8638 lookfor = LOOKFOR_ENUM_OR_INIT; 8639 cont_amount = cin_first_id_amount(); 8640 } 8641 } 8642 else 8643 { 8644 if (lookfor == LOOKFOR_INITIAL 8645 && *l != NUL 8646 && l[STRLEN(l) - 1] == '\\') 8647 /* XXX */ 8648 cont_amount = cin_get_equal_amount( 8649 curwin->w_cursor.lnum); 8650 if (lookfor != LOOKFOR_TERM 8651 && lookfor != LOOKFOR_JS_KEY 8652 && lookfor != LOOKFOR_COMMA) 8653 lookfor = LOOKFOR_UNTERM; 8654 } 8655 } 8656 } 8657 } 8658 8659 /* 8660 * Check if we are after a while (cond); 8661 * If so: Ignore until the matching "do". 8662 */ 8663 else if (cin_iswhileofdo_end(terminated)) /* XXX */ 8664 { 8665 /* 8666 * Found an unterminated line after a while ();, line up 8667 * with the last one. 8668 * while (cond); 8669 * 100 + <- line up with this one 8670 * -> here; 8671 */ 8672 if (lookfor == LOOKFOR_UNTERM 8673 || lookfor == LOOKFOR_ENUM_OR_INIT) 8674 { 8675 if (cont_amount > 0) 8676 amount = cont_amount; 8677 else 8678 amount += ind_continuation; 8679 break; 8680 } 8681 8682 if (whilelevel == 0) 8683 { 8684 lookfor = LOOKFOR_TERM; 8685 amount = get_indent(); /* XXX */ 8686 if (theline[0] == '{') 8687 amount += curbuf->b_ind_open_extra; 8688 } 8689 ++whilelevel; 8690 } 8691 8692 /* 8693 * We are after a "normal" statement. 8694 * If we had another statement we can stop now and use the 8695 * indent of that other statement. 8696 * Otherwise the indent of the current statement may be used, 8697 * search backwards for the next "normal" statement. 8698 */ 8699 else 8700 { 8701 /* 8702 * Skip single break line, if before a switch label. It 8703 * may be lined up with the case label. 8704 */ 8705 if (lookfor == LOOKFOR_NOBREAK 8706 && cin_isbreak(skipwhite(ml_get_curline()))) 8707 { 8708 lookfor = LOOKFOR_ANY; 8709 continue; 8710 } 8711 8712 /* 8713 * Handle "do {" line. 8714 */ 8715 if (whilelevel > 0) 8716 { 8717 l = cin_skipcomment(ml_get_curline()); 8718 if (cin_isdo(l)) 8719 { 8720 amount = get_indent(); /* XXX */ 8721 --whilelevel; 8722 continue; 8723 } 8724 } 8725 8726 /* 8727 * Found a terminated line above an unterminated line. Add 8728 * the amount for a continuation line. 8729 * x = 1; 8730 * y = foo + 8731 * -> here; 8732 * or 8733 * int x = 1; 8734 * int foo, 8735 * -> here; 8736 */ 8737 if (lookfor == LOOKFOR_UNTERM 8738 || lookfor == LOOKFOR_ENUM_OR_INIT) 8739 { 8740 if (cont_amount > 0) 8741 amount = cont_amount; 8742 else 8743 amount += ind_continuation; 8744 break; 8745 } 8746 8747 /* 8748 * Found a terminated line above a terminated line or "if" 8749 * etc. line. Use the amount of the line below us. 8750 * x = 1; x = 1; 8751 * if (asdf) y = 2; 8752 * while (asdf) ->here; 8753 * here; 8754 * ->foo; 8755 */ 8756 if (lookfor == LOOKFOR_TERM) 8757 { 8758 if (!lookfor_break && whilelevel == 0) 8759 break; 8760 } 8761 8762 /* 8763 * First line above the one we're indenting is terminated. 8764 * To know what needs to be done look further backward for 8765 * a terminated line. 8766 */ 8767 else 8768 { 8769 /* 8770 * position the cursor over the rightmost paren, so 8771 * that matching it will take us back to the start of 8772 * the line. Helps for: 8773 * func(asdr, 8774 * asdfasdf); 8775 * here; 8776 */ 8777 term_again: 8778 l = ml_get_curline(); 8779 if (find_last_paren(l, '(', ')') 8780 && (trypos = find_match_paren( 8781 curbuf->b_ind_maxparen)) != NULL) 8782 { 8783 /* 8784 * Check if we are on a case label now. This is 8785 * handled above. 8786 * case xx: if ( asdf && 8787 * asdf) 8788 */ 8789 curwin->w_cursor = *trypos; 8790 l = ml_get_curline(); 8791 if (cin_iscase(l, FALSE) || cin_isscopedecl(l)) 8792 { 8793 ++curwin->w_cursor.lnum; 8794 curwin->w_cursor.col = 0; 8795 continue; 8796 } 8797 } 8798 8799 /* When aligning with the case statement, don't align 8800 * with a statement after it. 8801 * case 1: { <-- don't use this { position 8802 * stat; 8803 * } 8804 * case 2: 8805 * stat; 8806 * } 8807 */ 8808 iscase = (curbuf->b_ind_keep_case_label 8809 && cin_iscase(l, FALSE)); 8810 8811 /* 8812 * Get indent and pointer to text for current line, 8813 * ignoring any jump label. 8814 */ 8815 amount = skip_label(curwin->w_cursor.lnum, &l); 8816 8817 if (theline[0] == '{') 8818 amount += curbuf->b_ind_open_extra; 8819 /* See remark above: "Only add b_ind_open_extra.." */ 8820 l = skipwhite(l); 8821 if (*l == '{') 8822 amount -= curbuf->b_ind_open_extra; 8823 lookfor = iscase ? LOOKFOR_ANY : LOOKFOR_TERM; 8824 8825 /* 8826 * When a terminated line starts with "else" skip to 8827 * the matching "if": 8828 * else 3; 8829 * indent this; 8830 * Need to use the scope of this "else". XXX 8831 * If whilelevel != 0 continue looking for a "do {". 8832 */ 8833 if (lookfor == LOOKFOR_TERM 8834 && *l != '}' 8835 && cin_iselse(l) 8836 && whilelevel == 0) 8837 { 8838 if ((trypos = find_start_brace()) == NULL 8839 || find_match(LOOKFOR_IF, trypos->lnum) 8840 == FAIL) 8841 break; 8842 continue; 8843 } 8844 8845 /* 8846 * If we're at the end of a block, skip to the start of 8847 * that block. 8848 */ 8849 l = ml_get_curline(); 8850 if (find_last_paren(l, '{', '}') /* XXX */ 8851 && (trypos = find_start_brace()) != NULL) 8852 { 8853 curwin->w_cursor = *trypos; 8854 /* if not "else {" check for terminated again */ 8855 /* but skip block for "} else {" */ 8856 l = cin_skipcomment(ml_get_curline()); 8857 if (*l == '}' || !cin_iselse(l)) 8858 goto term_again; 8859 ++curwin->w_cursor.lnum; 8860 curwin->w_cursor.col = 0; 8861 } 8862 } 8863 } 8864 } 8865 } 8866 } 8867 8868 /* add extra indent for a comment */ 8869 if (cin_iscomment(theline)) 8870 amount += curbuf->b_ind_comment; 8871 8872 /* subtract extra left-shift for jump labels */ 8873 if (curbuf->b_ind_jump_label > 0 && original_line_islabel) 8874 amount -= curbuf->b_ind_jump_label; 8875 8876 goto theend; 8877 } 8878 8879 /* 8880 * ok -- we're not inside any sort of structure at all! 8881 * 8882 * This means we're at the top level, and everything should 8883 * basically just match where the previous line is, except 8884 * for the lines immediately following a function declaration, 8885 * which are K&R-style parameters and need to be indented. 8886 * 8887 * if our line starts with an open brace, forget about any 8888 * prevailing indent and make sure it looks like the start 8889 * of a function 8890 */ 8891 8892 if (theline[0] == '{') 8893 { 8894 amount = curbuf->b_ind_first_open; 8895 goto theend; 8896 } 8897 8898 /* 8899 * If the NEXT line is a function declaration, the current 8900 * line needs to be indented as a function type spec. 8901 * Don't do this if the current line looks like a comment or if the 8902 * current line is terminated, ie. ends in ';', or if the current line 8903 * contains { or }: "void f() {\n if (1)" 8904 */ 8905 if (cur_curpos.lnum < curbuf->b_ml.ml_line_count 8906 && !cin_nocode(theline) 8907 && vim_strchr(theline, '{') == NULL 8908 && vim_strchr(theline, '}') == NULL 8909 && !cin_ends_in(theline, (char_u *)":", NULL) 8910 && !cin_ends_in(theline, (char_u *)",", NULL) 8911 && cin_isfuncdecl(NULL, cur_curpos.lnum + 1, 8912 cur_curpos.lnum + 1) 8913 && !cin_isterminated(theline, FALSE, TRUE)) 8914 { 8915 amount = curbuf->b_ind_func_type; 8916 goto theend; 8917 } 8918 8919 /* search backwards until we find something we recognize */ 8920 amount = 0; 8921 curwin->w_cursor = cur_curpos; 8922 while (curwin->w_cursor.lnum > 1) 8923 { 8924 curwin->w_cursor.lnum--; 8925 curwin->w_cursor.col = 0; 8926 8927 l = ml_get_curline(); 8928 8929 /* 8930 * If we're in a comment or raw string now, skip to the start 8931 * of it. 8932 */ /* XXX */ 8933 if ((trypos = ind_find_start_CORS()) != NULL) 8934 { 8935 curwin->w_cursor.lnum = trypos->lnum + 1; 8936 curwin->w_cursor.col = 0; 8937 continue; 8938 } 8939 8940 /* 8941 * Are we at the start of a cpp base class declaration or 8942 * constructor initialization? 8943 */ /* XXX */ 8944 n = FALSE; 8945 if (curbuf->b_ind_cpp_baseclass != 0 && theline[0] != '{') 8946 { 8947 n = cin_is_cpp_baseclass(&cache_cpp_baseclass); 8948 l = ml_get_curline(); 8949 } 8950 if (n) 8951 { 8952 /* XXX */ 8953 amount = get_baseclass_amount(cache_cpp_baseclass.lpos.col); 8954 break; 8955 } 8956 8957 /* 8958 * Skip preprocessor directives and blank lines. 8959 */ 8960 if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)) 8961 continue; 8962 8963 if (cin_nocode(l)) 8964 continue; 8965 8966 /* 8967 * If the previous line ends in ',', use one level of 8968 * indentation: 8969 * int foo, 8970 * bar; 8971 * do this before checking for '}' in case of eg. 8972 * enum foobar 8973 * { 8974 * ... 8975 * } foo, 8976 * bar; 8977 */ 8978 n = 0; 8979 if (cin_ends_in(l, (char_u *)",", NULL) 8980 || (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\')) 8981 { 8982 /* take us back to opening paren */ 8983 if (find_last_paren(l, '(', ')') 8984 && (trypos = find_match_paren( 8985 curbuf->b_ind_maxparen)) != NULL) 8986 curwin->w_cursor = *trypos; 8987 8988 /* For a line ending in ',' that is a continuation line go 8989 * back to the first line with a backslash: 8990 * char *foo = "bla\ 8991 * bla", 8992 * here; 8993 */ 8994 while (n == 0 && curwin->w_cursor.lnum > 1) 8995 { 8996 l = ml_get(curwin->w_cursor.lnum - 1); 8997 if (*l == NUL || l[STRLEN(l) - 1] != '\\') 8998 break; 8999 --curwin->w_cursor.lnum; 9000 curwin->w_cursor.col = 0; 9001 } 9002 9003 amount = get_indent(); /* XXX */ 9004 9005 if (amount == 0) 9006 amount = cin_first_id_amount(); 9007 if (amount == 0) 9008 amount = ind_continuation; 9009 break; 9010 } 9011 9012 /* 9013 * If the line looks like a function declaration, and we're 9014 * not in a comment, put it the left margin. 9015 */ 9016 if (cin_isfuncdecl(NULL, cur_curpos.lnum, 0)) /* XXX */ 9017 break; 9018 l = ml_get_curline(); 9019 9020 /* 9021 * Finding the closing '}' of a previous function. Put 9022 * current line at the left margin. For when 'cino' has "fs". 9023 */ 9024 if (*skipwhite(l) == '}') 9025 break; 9026 9027 /* (matching {) 9028 * If the previous line ends on '};' (maybe followed by 9029 * comments) align at column 0. For example: 9030 * char *string_array[] = { "foo", 9031 * / * x * / "b};ar" }; / * foobar * / 9032 */ 9033 if (cin_ends_in(l, (char_u *)"};", NULL)) 9034 break; 9035 9036 /* 9037 * If the previous line ends on '[' we are probably in an 9038 * array constant: 9039 * something = [ 9040 * 234, <- extra indent 9041 */ 9042 if (cin_ends_in(l, (char_u *)"[", NULL)) 9043 { 9044 amount = get_indent() + ind_continuation; 9045 break; 9046 } 9047 9048 /* 9049 * Find a line only has a semicolon that belongs to a previous 9050 * line ending in '}', e.g. before an #endif. Don't increase 9051 * indent then. 9052 */ 9053 if (*(look = skipwhite(l)) == ';' && cin_nocode(look + 1)) 9054 { 9055 pos_T curpos_save = curwin->w_cursor; 9056 9057 while (curwin->w_cursor.lnum > 1) 9058 { 9059 look = ml_get(--curwin->w_cursor.lnum); 9060 if (!(cin_nocode(look) || cin_ispreproc_cont( 9061 &look, &curwin->w_cursor.lnum, &amount))) 9062 break; 9063 } 9064 if (curwin->w_cursor.lnum > 0 9065 && cin_ends_in(look, (char_u *)"}", NULL)) 9066 break; 9067 9068 curwin->w_cursor = curpos_save; 9069 } 9070 9071 /* 9072 * If the PREVIOUS line is a function declaration, the current 9073 * line (and the ones that follow) needs to be indented as 9074 * parameters. 9075 */ 9076 if (cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0)) 9077 { 9078 amount = curbuf->b_ind_param; 9079 break; 9080 } 9081 9082 /* 9083 * If the previous line ends in ';' and the line before the 9084 * previous line ends in ',' or '\', ident to column zero: 9085 * int foo, 9086 * bar; 9087 * indent_to_0 here; 9088 */ 9089 if (cin_ends_in(l, (char_u *)";", NULL)) 9090 { 9091 l = ml_get(curwin->w_cursor.lnum - 1); 9092 if (cin_ends_in(l, (char_u *)",", NULL) 9093 || (*l != NUL && l[STRLEN(l) - 1] == '\\')) 9094 break; 9095 l = ml_get_curline(); 9096 } 9097 9098 /* 9099 * Doesn't look like anything interesting -- so just 9100 * use the indent of this line. 9101 * 9102 * Position the cursor over the rightmost paren, so that 9103 * matching it will take us back to the start of the line. 9104 */ 9105 find_last_paren(l, '(', ')'); 9106 9107 if ((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) 9108 curwin->w_cursor = *trypos; 9109 amount = get_indent(); /* XXX */ 9110 break; 9111 } 9112 9113 /* add extra indent for a comment */ 9114 if (cin_iscomment(theline)) 9115 amount += curbuf->b_ind_comment; 9116 9117 /* add extra indent if the previous line ended in a backslash: 9118 * "asdfasdf\ 9119 * here"; 9120 * char *foo = "asdf\ 9121 * here"; 9122 */ 9123 if (cur_curpos.lnum > 1) 9124 { 9125 l = ml_get(cur_curpos.lnum - 1); 9126 if (*l != NUL && l[STRLEN(l) - 1] == '\\') 9127 { 9128 cur_amount = cin_get_equal_amount(cur_curpos.lnum - 1); 9129 if (cur_amount > 0) 9130 amount = cur_amount; 9131 else if (cur_amount == 0) 9132 amount += ind_continuation; 9133 } 9134 } 9135 9136 theend: 9137 if (amount < 0) 9138 amount = 0; 9139 9140 laterend: 9141 /* put the cursor back where it belongs */ 9142 curwin->w_cursor = cur_curpos; 9143 9144 vim_free(linecopy); 9145 9146 return amount; 9147 } 9148 9149 static int 9150 find_match(int lookfor, linenr_T ourscope) 9151 { 9152 char_u *look; 9153 pos_T *theirscope; 9154 char_u *mightbeif; 9155 int elselevel; 9156 int whilelevel; 9157 9158 if (lookfor == LOOKFOR_IF) 9159 { 9160 elselevel = 1; 9161 whilelevel = 0; 9162 } 9163 else 9164 { 9165 elselevel = 0; 9166 whilelevel = 1; 9167 } 9168 9169 curwin->w_cursor.col = 0; 9170 9171 while (curwin->w_cursor.lnum > ourscope + 1) 9172 { 9173 curwin->w_cursor.lnum--; 9174 curwin->w_cursor.col = 0; 9175 9176 look = cin_skipcomment(ml_get_curline()); 9177 if (cin_iselse(look) 9178 || cin_isif(look) 9179 || cin_isdo(look) /* XXX */ 9180 || cin_iswhileofdo(look, curwin->w_cursor.lnum)) 9181 { 9182 /* 9183 * if we've gone outside the braces entirely, 9184 * we must be out of scope... 9185 */ 9186 theirscope = find_start_brace(); /* XXX */ 9187 if (theirscope == NULL) 9188 break; 9189 9190 /* 9191 * and if the brace enclosing this is further 9192 * back than the one enclosing the else, we're 9193 * out of luck too. 9194 */ 9195 if (theirscope->lnum < ourscope) 9196 break; 9197 9198 /* 9199 * and if they're enclosed in a *deeper* brace, 9200 * then we can ignore it because it's in a 9201 * different scope... 9202 */ 9203 if (theirscope->lnum > ourscope) 9204 continue; 9205 9206 /* 9207 * if it was an "else" (that's not an "else if") 9208 * then we need to go back to another if, so 9209 * increment elselevel 9210 */ 9211 look = cin_skipcomment(ml_get_curline()); 9212 if (cin_iselse(look)) 9213 { 9214 mightbeif = cin_skipcomment(look + 4); 9215 if (!cin_isif(mightbeif)) 9216 ++elselevel; 9217 continue; 9218 } 9219 9220 /* 9221 * if it was a "while" then we need to go back to 9222 * another "do", so increment whilelevel. XXX 9223 */ 9224 if (cin_iswhileofdo(look, curwin->w_cursor.lnum)) 9225 { 9226 ++whilelevel; 9227 continue; 9228 } 9229 9230 /* If it's an "if" decrement elselevel */ 9231 look = cin_skipcomment(ml_get_curline()); 9232 if (cin_isif(look)) 9233 { 9234 elselevel--; 9235 /* 9236 * When looking for an "if" ignore "while"s that 9237 * get in the way. 9238 */ 9239 if (elselevel == 0 && lookfor == LOOKFOR_IF) 9240 whilelevel = 0; 9241 } 9242 9243 /* If it's a "do" decrement whilelevel */ 9244 if (cin_isdo(look)) 9245 whilelevel--; 9246 9247 /* 9248 * if we've used up all the elses, then 9249 * this must be the if that we want! 9250 * match the indent level of that if. 9251 */ 9252 if (elselevel <= 0 && whilelevel <= 0) 9253 { 9254 return OK; 9255 } 9256 } 9257 } 9258 return FAIL; 9259 } 9260 9261 # if defined(FEAT_EVAL) || defined(PROTO) 9262 /* 9263 * Get indent level from 'indentexpr'. 9264 */ 9265 int 9266 get_expr_indent(void) 9267 { 9268 int indent = -1; 9269 char_u *inde_copy; 9270 pos_T save_pos; 9271 colnr_T save_curswant; 9272 int save_set_curswant; 9273 int save_State; 9274 int use_sandbox = was_set_insecurely((char_u *)"indentexpr", 9275 OPT_LOCAL); 9276 9277 /* Save and restore cursor position and curswant, in case it was changed 9278 * via :normal commands */ 9279 save_pos = curwin->w_cursor; 9280 save_curswant = curwin->w_curswant; 9281 save_set_curswant = curwin->w_set_curswant; 9282 set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum); 9283 if (use_sandbox) 9284 ++sandbox; 9285 ++textlock; 9286 9287 /* Need to make a copy, the 'indentexpr' option could be changed while 9288 * evaluating it. */ 9289 inde_copy = vim_strsave(curbuf->b_p_inde); 9290 if (inde_copy != NULL) 9291 { 9292 indent = (int)eval_to_number(inde_copy); 9293 vim_free(inde_copy); 9294 } 9295 9296 if (use_sandbox) 9297 --sandbox; 9298 --textlock; 9299 9300 /* Restore the cursor position so that 'indentexpr' doesn't need to. 9301 * Pretend to be in Insert mode, allow cursor past end of line for "o" 9302 * command. */ 9303 save_State = State; 9304 State = INSERT; 9305 curwin->w_cursor = save_pos; 9306 curwin->w_curswant = save_curswant; 9307 curwin->w_set_curswant = save_set_curswant; 9308 check_cursor(); 9309 State = save_State; 9310 9311 /* If there is an error, just keep the current indent. */ 9312 if (indent < 0) 9313 indent = get_indent(); 9314 9315 return indent; 9316 } 9317 # endif 9318 9319 #endif /* FEAT_CINDENT */ 9320 9321 #if defined(FEAT_LISP) || defined(PROTO) 9322 9323 static int lisp_match(char_u *p); 9324 9325 static int 9326 lisp_match(char_u *p) 9327 { 9328 char_u buf[LSIZE]; 9329 int len; 9330 char_u *word = *curbuf->b_p_lw != NUL ? curbuf->b_p_lw : p_lispwords; 9331 9332 while (*word != NUL) 9333 { 9334 (void)copy_option_part(&word, buf, LSIZE, ","); 9335 len = (int)STRLEN(buf); 9336 if (STRNCMP(buf, p, len) == 0 && p[len] == ' ') 9337 return TRUE; 9338 } 9339 return FALSE; 9340 } 9341 9342 /* 9343 * When 'p' is present in 'cpoptions, a Vi compatible method is used. 9344 * The incompatible newer method is quite a bit better at indenting 9345 * code in lisp-like languages than the traditional one; it's still 9346 * mostly heuristics however -- Dirk van Deun, [email protected] 9347 * 9348 * TODO: 9349 * Findmatch() should be adapted for lisp, also to make showmatch 9350 * work correctly: now (v5.3) it seems all C/C++ oriented: 9351 * - it does not recognize the #\( and #\) notations as character literals 9352 * - it doesn't know about comments starting with a semicolon 9353 * - it incorrectly interprets '(' as a character literal 9354 * All this messes up get_lisp_indent in some rare cases. 9355 * Update from Sergey Khorev: 9356 * I tried to fix the first two issues. 9357 */ 9358 int 9359 get_lisp_indent(void) 9360 { 9361 pos_T *pos, realpos, paren; 9362 int amount; 9363 char_u *that; 9364 colnr_T col; 9365 colnr_T firsttry; 9366 int parencount, quotecount; 9367 int vi_lisp; 9368 9369 /* Set vi_lisp to use the vi-compatible method */ 9370 vi_lisp = (vim_strchr(p_cpo, CPO_LISP) != NULL); 9371 9372 realpos = curwin->w_cursor; 9373 curwin->w_cursor.col = 0; 9374 9375 if ((pos = findmatch(NULL, '(')) == NULL) 9376 pos = findmatch(NULL, '['); 9377 else 9378 { 9379 paren = *pos; 9380 pos = findmatch(NULL, '['); 9381 if (pos == NULL || LT_POSP(pos, &paren)) 9382 pos = &paren; 9383 } 9384 if (pos != NULL) 9385 { 9386 /* Extra trick: Take the indent of the first previous non-white 9387 * line that is at the same () level. */ 9388 amount = -1; 9389 parencount = 0; 9390 9391 while (--curwin->w_cursor.lnum >= pos->lnum) 9392 { 9393 if (linewhite(curwin->w_cursor.lnum)) 9394 continue; 9395 for (that = ml_get_curline(); *that != NUL; ++that) 9396 { 9397 if (*that == ';') 9398 { 9399 while (*(that + 1) != NUL) 9400 ++that; 9401 continue; 9402 } 9403 if (*that == '\\') 9404 { 9405 if (*(that + 1) != NUL) 9406 ++that; 9407 continue; 9408 } 9409 if (*that == '"' && *(that + 1) != NUL) 9410 { 9411 while (*++that && *that != '"') 9412 { 9413 /* skipping escaped characters in the string */ 9414 if (*that == '\\') 9415 { 9416 if (*++that == NUL) 9417 break; 9418 if (that[1] == NUL) 9419 { 9420 ++that; 9421 break; 9422 } 9423 } 9424 } 9425 } 9426 if (*that == '(' || *that == '[') 9427 ++parencount; 9428 else if (*that == ')' || *that == ']') 9429 --parencount; 9430 } 9431 if (parencount == 0) 9432 { 9433 amount = get_indent(); 9434 break; 9435 } 9436 } 9437 9438 if (amount == -1) 9439 { 9440 curwin->w_cursor.lnum = pos->lnum; 9441 curwin->w_cursor.col = pos->col; 9442 col = pos->col; 9443 9444 that = ml_get_curline(); 9445 9446 if (vi_lisp && get_indent() == 0) 9447 amount = 2; 9448 else 9449 { 9450 char_u *line = that; 9451 9452 amount = 0; 9453 while (*that && col) 9454 { 9455 amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount); 9456 col--; 9457 } 9458 9459 /* 9460 * Some keywords require "body" indenting rules (the 9461 * non-standard-lisp ones are Scheme special forms): 9462 * 9463 * (let ((a 1)) instead (let ((a 1)) 9464 * (...)) of (...)) 9465 */ 9466 9467 if (!vi_lisp && (*that == '(' || *that == '[') 9468 && lisp_match(that + 1)) 9469 amount += 2; 9470 else 9471 { 9472 that++; 9473 amount++; 9474 firsttry = amount; 9475 9476 while (VIM_ISWHITE(*that)) 9477 { 9478 amount += lbr_chartabsize(line, that, (colnr_T)amount); 9479 ++that; 9480 } 9481 9482 if (*that && *that != ';') /* not a comment line */ 9483 { 9484 /* test *that != '(' to accommodate first let/do 9485 * argument if it is more than one line */ 9486 if (!vi_lisp && *that != '(' && *that != '[') 9487 firsttry++; 9488 9489 parencount = 0; 9490 quotecount = 0; 9491 9492 if (vi_lisp 9493 || (*that != '"' 9494 && *that != '\'' 9495 && *that != '#' 9496 && (*that < '0' || *that > '9'))) 9497 { 9498 while (*that 9499 && (!VIM_ISWHITE(*that) 9500 || quotecount 9501 || parencount) 9502 && (!((*that == '(' || *that == '[') 9503 && !quotecount 9504 && !parencount 9505 && vi_lisp))) 9506 { 9507 if (*that == '"') 9508 quotecount = !quotecount; 9509 if ((*that == '(' || *that == '[') 9510 && !quotecount) 9511 ++parencount; 9512 if ((*that == ')' || *that == ']') 9513 && !quotecount) 9514 --parencount; 9515 if (*that == '\\' && *(that+1) != NUL) 9516 amount += lbr_chartabsize_adv( 9517 line, &that, (colnr_T)amount); 9518 amount += lbr_chartabsize_adv( 9519 line, &that, (colnr_T)amount); 9520 } 9521 } 9522 while (VIM_ISWHITE(*that)) 9523 { 9524 amount += lbr_chartabsize( 9525 line, that, (colnr_T)amount); 9526 that++; 9527 } 9528 if (!*that || *that == ';') 9529 amount = firsttry; 9530 } 9531 } 9532 } 9533 } 9534 } 9535 else 9536 amount = 0; /* no matching '(' or '[' found, use zero indent */ 9537 9538 curwin->w_cursor = realpos; 9539 9540 return amount; 9541 } 9542 #endif /* FEAT_LISP */ 9543 9544 void 9545 prepare_to_exit(void) 9546 { 9547 #if defined(SIGHUP) && defined(SIG_IGN) 9548 /* Ignore SIGHUP, because a dropped connection causes a read error, which 9549 * makes Vim exit and then handling SIGHUP causes various reentrance 9550 * problems. */ 9551 signal(SIGHUP, SIG_IGN); 9552 #endif 9553 9554 #ifdef FEAT_GUI 9555 if (gui.in_use) 9556 { 9557 gui.dying = TRUE; 9558 out_trash(); /* trash any pending output */ 9559 } 9560 else 9561 #endif 9562 { 9563 windgoto((int)Rows - 1, 0); 9564 9565 /* 9566 * Switch terminal mode back now, so messages end up on the "normal" 9567 * screen (if there are two screens). 9568 */ 9569 settmode(TMODE_COOK); 9570 stoptermcap(); 9571 out_flush(); 9572 } 9573 } 9574 9575 /* 9576 * Preserve files and exit. 9577 * When called IObuff must contain a message. 9578 * NOTE: This may be called from deathtrap() in a signal handler, avoid unsafe 9579 * functions, such as allocating memory. 9580 */ 9581 void 9582 preserve_exit(void) 9583 { 9584 buf_T *buf; 9585 9586 prepare_to_exit(); 9587 9588 /* Setting this will prevent free() calls. That avoids calling free() 9589 * recursively when free() was invoked with a bad pointer. */ 9590 really_exiting = TRUE; 9591 9592 out_str(IObuff); 9593 screen_start(); /* don't know where cursor is now */ 9594 out_flush(); 9595 9596 ml_close_notmod(); /* close all not-modified buffers */ 9597 9598 FOR_ALL_BUFFERS(buf) 9599 { 9600 if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) 9601 { 9602 OUT_STR("Vim: preserving files...\n"); 9603 screen_start(); /* don't know where cursor is now */ 9604 out_flush(); 9605 ml_sync_all(FALSE, FALSE); /* preserve all swap files */ 9606 break; 9607 } 9608 } 9609 9610 ml_close_all(FALSE); /* close all memfiles, without deleting */ 9611 9612 OUT_STR("Vim: Finished.\n"); 9613 9614 getout(1); 9615 } 9616 9617 /* 9618 * return TRUE if "fname" exists. 9619 */ 9620 int 9621 vim_fexists(char_u *fname) 9622 { 9623 stat_T st; 9624 9625 if (mch_stat((char *)fname, &st)) 9626 return FALSE; 9627 return TRUE; 9628 } 9629 9630 /* 9631 * Check for CTRL-C pressed, but only once in a while. 9632 * Should be used instead of ui_breakcheck() for functions that check for 9633 * each line in the file. Calling ui_breakcheck() each time takes too much 9634 * time, because it can be a system call. 9635 */ 9636 9637 #ifndef BREAKCHECK_SKIP 9638 # ifdef FEAT_GUI /* assume the GUI only runs on fast computers */ 9639 # define BREAKCHECK_SKIP 200 9640 # else 9641 # define BREAKCHECK_SKIP 32 9642 # endif 9643 #endif 9644 9645 static int breakcheck_count = 0; 9646 9647 void 9648 line_breakcheck(void) 9649 { 9650 if (++breakcheck_count >= BREAKCHECK_SKIP) 9651 { 9652 breakcheck_count = 0; 9653 ui_breakcheck(); 9654 } 9655 } 9656 9657 /* 9658 * Like line_breakcheck() but check 10 times less often. 9659 */ 9660 void 9661 fast_breakcheck(void) 9662 { 9663 if (++breakcheck_count >= BREAKCHECK_SKIP * 10) 9664 { 9665 breakcheck_count = 0; 9666 ui_breakcheck(); 9667 } 9668 } 9669 9670 /* 9671 * Invoke expand_wildcards() for one pattern. 9672 * Expand items like "%:h" before the expansion. 9673 * Returns OK or FAIL. 9674 */ 9675 int 9676 expand_wildcards_eval( 9677 char_u **pat, /* pointer to input pattern */ 9678 int *num_file, /* resulting number of files */ 9679 char_u ***file, /* array of resulting files */ 9680 int flags) /* EW_DIR, etc. */ 9681 { 9682 int ret = FAIL; 9683 char_u *eval_pat = NULL; 9684 char_u *exp_pat = *pat; 9685 char_u *ignored_msg; 9686 int usedlen; 9687 9688 if (*exp_pat == '%' || *exp_pat == '#' || *exp_pat == '<') 9689 { 9690 ++emsg_off; 9691 eval_pat = eval_vars(exp_pat, exp_pat, &usedlen, 9692 NULL, &ignored_msg, NULL); 9693 --emsg_off; 9694 if (eval_pat != NULL) 9695 exp_pat = concat_str(eval_pat, exp_pat + usedlen); 9696 } 9697 9698 if (exp_pat != NULL) 9699 ret = expand_wildcards(1, &exp_pat, num_file, file, flags); 9700 9701 if (eval_pat != NULL) 9702 { 9703 vim_free(exp_pat); 9704 vim_free(eval_pat); 9705 } 9706 9707 return ret; 9708 } 9709 9710 /* 9711 * Expand wildcards. Calls gen_expand_wildcards() and removes files matching 9712 * 'wildignore'. 9713 * Returns OK or FAIL. When FAIL then "num_files" won't be set. 9714 */ 9715 int 9716 expand_wildcards( 9717 int num_pat, /* number of input patterns */ 9718 char_u **pat, /* array of input patterns */ 9719 int *num_files, /* resulting number of files */ 9720 char_u ***files, /* array of resulting files */ 9721 int flags) /* EW_DIR, etc. */ 9722 { 9723 int retval; 9724 int i, j; 9725 char_u *p; 9726 int non_suf_match; /* number without matching suffix */ 9727 9728 retval = gen_expand_wildcards(num_pat, pat, num_files, files, flags); 9729 9730 /* When keeping all matches, return here */ 9731 if ((flags & EW_KEEPALL) || retval == FAIL) 9732 return retval; 9733 9734 #ifdef FEAT_WILDIGN 9735 /* 9736 * Remove names that match 'wildignore'. 9737 */ 9738 if (*p_wig) 9739 { 9740 char_u *ffname; 9741 9742 /* check all files in (*files)[] */ 9743 for (i = 0; i < *num_files; ++i) 9744 { 9745 ffname = FullName_save((*files)[i], FALSE); 9746 if (ffname == NULL) /* out of memory */ 9747 break; 9748 # ifdef VMS 9749 vms_remove_version(ffname); 9750 # endif 9751 if (match_file_list(p_wig, (*files)[i], ffname)) 9752 { 9753 /* remove this matching file from the list */ 9754 vim_free((*files)[i]); 9755 for (j = i; j + 1 < *num_files; ++j) 9756 (*files)[j] = (*files)[j + 1]; 9757 --*num_files; 9758 --i; 9759 } 9760 vim_free(ffname); 9761 } 9762 9763 /* If the number of matches is now zero, we fail. */ 9764 if (*num_files == 0) 9765 { 9766 vim_free(*files); 9767 *files = NULL; 9768 return FAIL; 9769 } 9770 } 9771 #endif 9772 9773 /* 9774 * Move the names where 'suffixes' match to the end. 9775 */ 9776 if (*num_files > 1) 9777 { 9778 non_suf_match = 0; 9779 for (i = 0; i < *num_files; ++i) 9780 { 9781 if (!match_suffix((*files)[i])) 9782 { 9783 /* 9784 * Move the name without matching suffix to the front 9785 * of the list. 9786 */ 9787 p = (*files)[i]; 9788 for (j = i; j > non_suf_match; --j) 9789 (*files)[j] = (*files)[j - 1]; 9790 (*files)[non_suf_match++] = p; 9791 } 9792 } 9793 } 9794 9795 return retval; 9796 } 9797 9798 /* 9799 * Return TRUE if "fname" matches with an entry in 'suffixes'. 9800 */ 9801 int 9802 match_suffix(char_u *fname) 9803 { 9804 int fnamelen, setsuflen; 9805 char_u *setsuf; 9806 #define MAXSUFLEN 30 /* maximum length of a file suffix */ 9807 char_u suf_buf[MAXSUFLEN]; 9808 9809 fnamelen = (int)STRLEN(fname); 9810 setsuflen = 0; 9811 for (setsuf = p_su; *setsuf; ) 9812 { 9813 setsuflen = copy_option_part(&setsuf, suf_buf, MAXSUFLEN, ".,"); 9814 if (setsuflen == 0) 9815 { 9816 char_u *tail = gettail(fname); 9817 9818 /* empty entry: match name without a '.' */ 9819 if (vim_strchr(tail, '.') == NULL) 9820 { 9821 setsuflen = 1; 9822 break; 9823 } 9824 } 9825 else 9826 { 9827 if (fnamelen >= setsuflen 9828 && fnamencmp(suf_buf, fname + fnamelen - setsuflen, 9829 (size_t)setsuflen) == 0) 9830 break; 9831 setsuflen = 0; 9832 } 9833 } 9834 return (setsuflen != 0); 9835 } 9836 9837 #if !defined(NO_EXPANDPATH) || defined(PROTO) 9838 9839 # ifdef VIM_BACKTICK 9840 static int vim_backtick(char_u *p); 9841 static int expand_backtick(garray_T *gap, char_u *pat, int flags); 9842 # endif 9843 9844 # if defined(WIN3264) 9845 /* 9846 * File name expansion code for MS-DOS, Win16 and Win32. It's here because 9847 * it's shared between these systems. 9848 */ 9849 # if defined(PROTO) 9850 # define _cdecl 9851 # else 9852 # ifdef __BORLANDC__ 9853 # define _cdecl _RTLENTRYF 9854 # endif 9855 # endif 9856 9857 /* 9858 * comparison function for qsort in dos_expandpath() 9859 */ 9860 static int _cdecl 9861 pstrcmp(const void *a, const void *b) 9862 { 9863 return (pathcmp(*(char **)a, *(char **)b, -1)); 9864 } 9865 9866 /* 9867 * Recursively expand one path component into all matching files and/or 9868 * directories. Adds matches to "gap". Handles "*", "?", "[a-z]", "**", etc. 9869 * Return the number of matches found. 9870 * "path" has backslashes before chars that are not to be expanded, starting 9871 * at "path[wildoff]". 9872 * Return the number of matches found. 9873 * NOTE: much of this is identical to unix_expandpath(), keep in sync! 9874 */ 9875 static int 9876 dos_expandpath( 9877 garray_T *gap, 9878 char_u *path, 9879 int wildoff, 9880 int flags, /* EW_* flags */ 9881 int didstar) /* expanded "**" once already */ 9882 { 9883 char_u *buf; 9884 char_u *path_end; 9885 char_u *p, *s, *e; 9886 int start_len = gap->ga_len; 9887 char_u *pat; 9888 regmatch_T regmatch; 9889 int starts_with_dot; 9890 int matches; 9891 int len; 9892 int starstar = FALSE; 9893 static int stardepth = 0; /* depth for "**" expansion */ 9894 WIN32_FIND_DATA fb; 9895 HANDLE hFind = (HANDLE)0; 9896 # ifdef FEAT_MBYTE 9897 WIN32_FIND_DATAW wfb; 9898 WCHAR *wn = NULL; /* UCS-2 name, NULL when not used. */ 9899 # endif 9900 char_u *matchname; 9901 int ok; 9902 9903 /* Expanding "**" may take a long time, check for CTRL-C. */ 9904 if (stardepth > 0) 9905 { 9906 ui_breakcheck(); 9907 if (got_int) 9908 return 0; 9909 } 9910 9911 /* Make room for file name. When doing encoding conversion the actual 9912 * length may be quite a bit longer, thus use the maximum possible length. */ 9913 buf = alloc((int)MAXPATHL); 9914 if (buf == NULL) 9915 return 0; 9916 9917 /* 9918 * Find the first part in the path name that contains a wildcard or a ~1. 9919 * Copy it into buf, including the preceding characters. 9920 */ 9921 p = buf; 9922 s = buf; 9923 e = NULL; 9924 path_end = path; 9925 while (*path_end != NUL) 9926 { 9927 /* May ignore a wildcard that has a backslash before it; it will 9928 * be removed by rem_backslash() or file_pat_to_reg_pat() below. */ 9929 if (path_end >= path + wildoff && rem_backslash(path_end)) 9930 *p++ = *path_end++; 9931 else if (*path_end == '\\' || *path_end == ':' || *path_end == '/') 9932 { 9933 if (e != NULL) 9934 break; 9935 s = p + 1; 9936 } 9937 else if (path_end >= path + wildoff 9938 && vim_strchr((char_u *)"*?[~", *path_end) != NULL) 9939 e = p; 9940 # ifdef FEAT_MBYTE 9941 if (has_mbyte) 9942 { 9943 len = (*mb_ptr2len)(path_end); 9944 STRNCPY(p, path_end, len); 9945 p += len; 9946 path_end += len; 9947 } 9948 else 9949 # endif 9950 *p++ = *path_end++; 9951 } 9952 e = p; 9953 *e = NUL; 9954 9955 /* now we have one wildcard component between s and e */ 9956 /* Remove backslashes between "wildoff" and the start of the wildcard 9957 * component. */ 9958 for (p = buf + wildoff; p < s; ++p) 9959 if (rem_backslash(p)) 9960 { 9961 STRMOVE(p, p + 1); 9962 --e; 9963 --s; 9964 } 9965 9966 /* Check for "**" between "s" and "e". */ 9967 for (p = s; p < e; ++p) 9968 if (p[0] == '*' && p[1] == '*') 9969 starstar = TRUE; 9970 9971 starts_with_dot = *s == '.'; 9972 pat = file_pat_to_reg_pat(s, e, NULL, FALSE); 9973 if (pat == NULL) 9974 { 9975 vim_free(buf); 9976 return 0; 9977 } 9978 9979 /* compile the regexp into a program */ 9980 if (flags & (EW_NOERROR | EW_NOTWILD)) 9981 ++emsg_silent; 9982 regmatch.rm_ic = TRUE; /* Always ignore case */ 9983 regmatch.regprog = vim_regcomp(pat, RE_MAGIC); 9984 if (flags & (EW_NOERROR | EW_NOTWILD)) 9985 --emsg_silent; 9986 vim_free(pat); 9987 9988 if (regmatch.regprog == NULL && (flags & EW_NOTWILD) == 0) 9989 { 9990 vim_free(buf); 9991 return 0; 9992 } 9993 9994 /* remember the pattern or file name being looked for */ 9995 matchname = vim_strsave(s); 9996 9997 /* If "**" is by itself, this is the first time we encounter it and more 9998 * is following then find matches without any directory. */ 9999 if (!didstar && stardepth < 100 && starstar && e - s == 2 10000 && *path_end == '/') 10001 { 10002 STRCPY(s, path_end + 1); 10003 ++stardepth; 10004 (void)dos_expandpath(gap, buf, (int)(s - buf), flags, TRUE); 10005 --stardepth; 10006 } 10007 10008 /* Scan all files in the directory with "dir/ *.*" */ 10009 STRCPY(s, "*.*"); 10010 # ifdef FEAT_MBYTE 10011 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) 10012 { 10013 /* The active codepage differs from 'encoding'. Attempt using the 10014 * wide function. If it fails because it is not implemented fall back 10015 * to the non-wide version (for Windows 98) */ 10016 wn = enc_to_utf16(buf, NULL); 10017 if (wn != NULL) 10018 { 10019 hFind = FindFirstFileW(wn, &wfb); 10020 if (hFind == INVALID_HANDLE_VALUE 10021 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 10022 { 10023 vim_free(wn); 10024 wn = NULL; 10025 } 10026 } 10027 } 10028 10029 if (wn == NULL) 10030 # endif 10031 hFind = FindFirstFile((LPCSTR)buf, &fb); 10032 ok = (hFind != INVALID_HANDLE_VALUE); 10033 10034 while (ok) 10035 { 10036 # ifdef FEAT_MBYTE 10037 if (wn != NULL) 10038 p = utf16_to_enc(wfb.cFileName, NULL); /* p is allocated here */ 10039 else 10040 # endif 10041 p = (char_u *)fb.cFileName; 10042 /* Ignore entries starting with a dot, unless when asked for. Accept 10043 * all entries found with "matchname". */ 10044 if ((p[0] != '.' || starts_with_dot 10045 || ((flags & EW_DODOT) 10046 && p[1] != NUL && (p[1] != '.' || p[2] != NUL))) 10047 && (matchname == NULL 10048 || (regmatch.regprog != NULL 10049 && vim_regexec(®match, p, (colnr_T)0)) 10050 || ((flags & EW_NOTWILD) 10051 && fnamencmp(path + (s - buf), p, e - s) == 0))) 10052 { 10053 STRCPY(s, p); 10054 len = (int)STRLEN(buf); 10055 10056 if (starstar && stardepth < 100) 10057 { 10058 /* For "**" in the pattern first go deeper in the tree to 10059 * find matches. */ 10060 STRCPY(buf + len, "/**"); 10061 STRCPY(buf + len + 3, path_end); 10062 ++stardepth; 10063 (void)dos_expandpath(gap, buf, len + 1, flags, TRUE); 10064 --stardepth; 10065 } 10066 10067 STRCPY(buf + len, path_end); 10068 if (mch_has_exp_wildcard(path_end)) 10069 { 10070 /* need to expand another component of the path */ 10071 /* remove backslashes for the remaining components only */ 10072 (void)dos_expandpath(gap, buf, len + 1, flags, FALSE); 10073 } 10074 else 10075 { 10076 /* no more wildcards, check if there is a match */ 10077 /* remove backslashes for the remaining components only */ 10078 if (*path_end != 0) 10079 backslash_halve(buf + len + 1); 10080 if (mch_getperm(buf) >= 0) /* add existing file */ 10081 addfile(gap, buf, flags); 10082 } 10083 } 10084 10085 # ifdef FEAT_MBYTE 10086 if (wn != NULL) 10087 { 10088 vim_free(p); 10089 ok = FindNextFileW(hFind, &wfb); 10090 } 10091 else 10092 # endif 10093 ok = FindNextFile(hFind, &fb); 10094 10095 /* If no more matches and no match was used, try expanding the name 10096 * itself. Finds the long name of a short filename. */ 10097 if (!ok && matchname != NULL && gap->ga_len == start_len) 10098 { 10099 STRCPY(s, matchname); 10100 FindClose(hFind); 10101 # ifdef FEAT_MBYTE 10102 if (wn != NULL) 10103 { 10104 vim_free(wn); 10105 wn = enc_to_utf16(buf, NULL); 10106 if (wn != NULL) 10107 hFind = FindFirstFileW(wn, &wfb); 10108 } 10109 if (wn == NULL) 10110 # endif 10111 hFind = FindFirstFile((LPCSTR)buf, &fb); 10112 ok = (hFind != INVALID_HANDLE_VALUE); 10113 vim_free(matchname); 10114 matchname = NULL; 10115 } 10116 } 10117 10118 FindClose(hFind); 10119 # ifdef FEAT_MBYTE 10120 vim_free(wn); 10121 # endif 10122 vim_free(buf); 10123 vim_regfree(regmatch.regprog); 10124 vim_free(matchname); 10125 10126 matches = gap->ga_len - start_len; 10127 if (matches > 0) 10128 qsort(((char_u **)gap->ga_data) + start_len, (size_t)matches, 10129 sizeof(char_u *), pstrcmp); 10130 return matches; 10131 } 10132 10133 int 10134 mch_expandpath( 10135 garray_T *gap, 10136 char_u *path, 10137 int flags) /* EW_* flags */ 10138 { 10139 return dos_expandpath(gap, path, 0, flags, FALSE); 10140 } 10141 # endif /* WIN3264 */ 10142 10143 #if (defined(UNIX) && !defined(VMS)) || defined(USE_UNIXFILENAME) \ 10144 || defined(PROTO) 10145 /* 10146 * Unix style wildcard expansion code. 10147 * It's here because it's used both for Unix and Mac. 10148 */ 10149 static int pstrcmp(const void *, const void *); 10150 10151 static int 10152 pstrcmp(const void *a, const void *b) 10153 { 10154 return (pathcmp(*(char **)a, *(char **)b, -1)); 10155 } 10156 10157 /* 10158 * Recursively expand one path component into all matching files and/or 10159 * directories. Adds matches to "gap". Handles "*", "?", "[a-z]", "**", etc. 10160 * "path" has backslashes before chars that are not to be expanded, starting 10161 * at "path + wildoff". 10162 * Return the number of matches found. 10163 * NOTE: much of this is identical to dos_expandpath(), keep in sync! 10164 */ 10165 int 10166 unix_expandpath( 10167 garray_T *gap, 10168 char_u *path, 10169 int wildoff, 10170 int flags, /* EW_* flags */ 10171 int didstar) /* expanded "**" once already */ 10172 { 10173 char_u *buf; 10174 char_u *path_end; 10175 char_u *p, *s, *e; 10176 int start_len = gap->ga_len; 10177 char_u *pat; 10178 regmatch_T regmatch; 10179 int starts_with_dot; 10180 int matches; 10181 int len; 10182 int starstar = FALSE; 10183 static int stardepth = 0; /* depth for "**" expansion */ 10184 10185 DIR *dirp; 10186 struct dirent *dp; 10187 10188 /* Expanding "**" may take a long time, check for CTRL-C. */ 10189 if (stardepth > 0) 10190 { 10191 ui_breakcheck(); 10192 if (got_int) 10193 return 0; 10194 } 10195 10196 /* make room for file name */ 10197 buf = alloc((int)STRLEN(path) + BASENAMELEN + 5); 10198 if (buf == NULL) 10199 return 0; 10200 10201 /* 10202 * Find the first part in the path name that contains a wildcard. 10203 * When EW_ICASE is set every letter is considered to be a wildcard. 10204 * Copy it into "buf", including the preceding characters. 10205 */ 10206 p = buf; 10207 s = buf; 10208 e = NULL; 10209 path_end = path; 10210 while (*path_end != NUL) 10211 { 10212 /* May ignore a wildcard that has a backslash before it; it will 10213 * be removed by rem_backslash() or file_pat_to_reg_pat() below. */ 10214 if (path_end >= path + wildoff && rem_backslash(path_end)) 10215 *p++ = *path_end++; 10216 else if (*path_end == '/') 10217 { 10218 if (e != NULL) 10219 break; 10220 s = p + 1; 10221 } 10222 else if (path_end >= path + wildoff 10223 && (vim_strchr((char_u *)"*?[{~$", *path_end) != NULL 10224 || (!p_fic && (flags & EW_ICASE) 10225 && isalpha(PTR2CHAR(path_end))))) 10226 e = p; 10227 #ifdef FEAT_MBYTE 10228 if (has_mbyte) 10229 { 10230 len = (*mb_ptr2len)(path_end); 10231 STRNCPY(p, path_end, len); 10232 p += len; 10233 path_end += len; 10234 } 10235 else 10236 #endif 10237 *p++ = *path_end++; 10238 } 10239 e = p; 10240 *e = NUL; 10241 10242 /* Now we have one wildcard component between "s" and "e". */ 10243 /* Remove backslashes between "wildoff" and the start of the wildcard 10244 * component. */ 10245 for (p = buf + wildoff; p < s; ++p) 10246 if (rem_backslash(p)) 10247 { 10248 STRMOVE(p, p + 1); 10249 --e; 10250 --s; 10251 } 10252 10253 /* Check for "**" between "s" and "e". */ 10254 for (p = s; p < e; ++p) 10255 if (p[0] == '*' && p[1] == '*') 10256 starstar = TRUE; 10257 10258 /* convert the file pattern to a regexp pattern */ 10259 starts_with_dot = *s == '.'; 10260 pat = file_pat_to_reg_pat(s, e, NULL, FALSE); 10261 if (pat == NULL) 10262 { 10263 vim_free(buf); 10264 return 0; 10265 } 10266 10267 /* compile the regexp into a program */ 10268 if (flags & EW_ICASE) 10269 regmatch.rm_ic = TRUE; /* 'wildignorecase' set */ 10270 else 10271 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */ 10272 if (flags & (EW_NOERROR | EW_NOTWILD)) 10273 ++emsg_silent; 10274 regmatch.regprog = vim_regcomp(pat, RE_MAGIC); 10275 if (flags & (EW_NOERROR | EW_NOTWILD)) 10276 --emsg_silent; 10277 vim_free(pat); 10278 10279 if (regmatch.regprog == NULL && (flags & EW_NOTWILD) == 0) 10280 { 10281 vim_free(buf); 10282 return 0; 10283 } 10284 10285 /* If "**" is by itself, this is the first time we encounter it and more 10286 * is following then find matches without any directory. */ 10287 if (!didstar && stardepth < 100 && starstar && e - s == 2 10288 && *path_end == '/') 10289 { 10290 STRCPY(s, path_end + 1); 10291 ++stardepth; 10292 (void)unix_expandpath(gap, buf, (int)(s - buf), flags, TRUE); 10293 --stardepth; 10294 } 10295 10296 /* open the directory for scanning */ 10297 *s = NUL; 10298 dirp = opendir(*buf == NUL ? "." : (char *)buf); 10299 10300 /* Find all matching entries */ 10301 if (dirp != NULL) 10302 { 10303 for (;;) 10304 { 10305 dp = readdir(dirp); 10306 if (dp == NULL) 10307 break; 10308 if ((dp->d_name[0] != '.' || starts_with_dot 10309 || ((flags & EW_DODOT) 10310 && dp->d_name[1] != NUL 10311 && (dp->d_name[1] != '.' || dp->d_name[2] != NUL))) 10312 && ((regmatch.regprog != NULL && vim_regexec(®match, 10313 (char_u *)dp->d_name, (colnr_T)0)) 10314 || ((flags & EW_NOTWILD) 10315 && fnamencmp(path + (s - buf), dp->d_name, e - s) == 0))) 10316 { 10317 STRCPY(s, dp->d_name); 10318 len = STRLEN(buf); 10319 10320 if (starstar && stardepth < 100) 10321 { 10322 /* For "**" in the pattern first go deeper in the tree to 10323 * find matches. */ 10324 STRCPY(buf + len, "/**"); 10325 STRCPY(buf + len + 3, path_end); 10326 ++stardepth; 10327 (void)unix_expandpath(gap, buf, len + 1, flags, TRUE); 10328 --stardepth; 10329 } 10330 10331 STRCPY(buf + len, path_end); 10332 if (mch_has_exp_wildcard(path_end)) /* handle more wildcards */ 10333 { 10334 /* need to expand another component of the path */ 10335 /* remove backslashes for the remaining components only */ 10336 (void)unix_expandpath(gap, buf, len + 1, flags, FALSE); 10337 } 10338 else 10339 { 10340 stat_T sb; 10341 10342 /* no more wildcards, check if there is a match */ 10343 /* remove backslashes for the remaining components only */ 10344 if (*path_end != NUL) 10345 backslash_halve(buf + len + 1); 10346 /* add existing file or symbolic link */ 10347 if ((flags & EW_ALLLINKS) ? mch_lstat((char *)buf, &sb) >= 0 10348 : mch_getperm(buf) >= 0) 10349 { 10350 #ifdef MACOS_CONVERT 10351 size_t precomp_len = STRLEN(buf)+1; 10352 char_u *precomp_buf = 10353 mac_precompose_path(buf, precomp_len, &precomp_len); 10354 10355 if (precomp_buf) 10356 { 10357 mch_memmove(buf, precomp_buf, precomp_len); 10358 vim_free(precomp_buf); 10359 } 10360 #endif 10361 addfile(gap, buf, flags); 10362 } 10363 } 10364 } 10365 } 10366 10367 closedir(dirp); 10368 } 10369 10370 vim_free(buf); 10371 vim_regfree(regmatch.regprog); 10372 10373 matches = gap->ga_len - start_len; 10374 if (matches > 0) 10375 qsort(((char_u **)gap->ga_data) + start_len, matches, 10376 sizeof(char_u *), pstrcmp); 10377 return matches; 10378 } 10379 #endif 10380 10381 #if defined(FEAT_SEARCHPATH) 10382 static int find_previous_pathsep(char_u *path, char_u **psep); 10383 static int is_unique(char_u *maybe_unique, garray_T *gap, int i); 10384 static void expand_path_option(char_u *curdir, garray_T *gap); 10385 static char_u *get_path_cutoff(char_u *fname, garray_T *gap); 10386 static void uniquefy_paths(garray_T *gap, char_u *pattern); 10387 static int expand_in_path(garray_T *gap, char_u *pattern, int flags); 10388 10389 /* 10390 * Moves "*psep" back to the previous path separator in "path". 10391 * Returns FAIL is "*psep" ends up at the beginning of "path". 10392 */ 10393 static int 10394 find_previous_pathsep(char_u *path, char_u **psep) 10395 { 10396 /* skip the current separator */ 10397 if (*psep > path && vim_ispathsep(**psep)) 10398 --*psep; 10399 10400 /* find the previous separator */ 10401 while (*psep > path) 10402 { 10403 if (vim_ispathsep(**psep)) 10404 return OK; 10405 MB_PTR_BACK(path, *psep); 10406 } 10407 10408 return FAIL; 10409 } 10410 10411 /* 10412 * Returns TRUE if "maybe_unique" is unique wrt other_paths in "gap". 10413 * "maybe_unique" is the end portion of "((char_u **)gap->ga_data)[i]". 10414 */ 10415 static int 10416 is_unique(char_u *maybe_unique, garray_T *gap, int i) 10417 { 10418 int j; 10419 int candidate_len; 10420 int other_path_len; 10421 char_u **other_paths = (char_u **)gap->ga_data; 10422 char_u *rival; 10423 10424 for (j = 0; j < gap->ga_len; j++) 10425 { 10426 if (j == i) 10427 continue; /* don't compare it with itself */ 10428 10429 candidate_len = (int)STRLEN(maybe_unique); 10430 other_path_len = (int)STRLEN(other_paths[j]); 10431 if (other_path_len < candidate_len) 10432 continue; /* it's different when it's shorter */ 10433 10434 rival = other_paths[j] + other_path_len - candidate_len; 10435 if (fnamecmp(maybe_unique, rival) == 0 10436 && (rival == other_paths[j] || vim_ispathsep(*(rival - 1)))) 10437 return FALSE; /* match */ 10438 } 10439 10440 return TRUE; /* no match found */ 10441 } 10442 10443 /* 10444 * Split the 'path' option into an array of strings in garray_T. Relative 10445 * paths are expanded to their equivalent fullpath. This includes the "." 10446 * (relative to current buffer directory) and empty path (relative to current 10447 * directory) notations. 10448 * 10449 * TODO: handle upward search (;) and path limiter (**N) notations by 10450 * expanding each into their equivalent path(s). 10451 */ 10452 static void 10453 expand_path_option(char_u *curdir, garray_T *gap) 10454 { 10455 char_u *path_option = *curbuf->b_p_path == NUL 10456 ? p_path : curbuf->b_p_path; 10457 char_u *buf; 10458 char_u *p; 10459 int len; 10460 10461 if ((buf = alloc((int)MAXPATHL)) == NULL) 10462 return; 10463 10464 while (*path_option != NUL) 10465 { 10466 copy_option_part(&path_option, buf, MAXPATHL, " ,"); 10467 10468 if (buf[0] == '.' && (buf[1] == NUL || vim_ispathsep(buf[1]))) 10469 { 10470 /* Relative to current buffer: 10471 * "/path/file" + "." -> "/path/" 10472 * "/path/file" + "./subdir" -> "/path/subdir" */ 10473 if (curbuf->b_ffname == NULL) 10474 continue; 10475 p = gettail(curbuf->b_ffname); 10476 len = (int)(p - curbuf->b_ffname); 10477 if (len + (int)STRLEN(buf) >= MAXPATHL) 10478 continue; 10479 if (buf[1] == NUL) 10480 buf[len] = NUL; 10481 else 10482 STRMOVE(buf + len, buf + 2); 10483 mch_memmove(buf, curbuf->b_ffname, len); 10484 simplify_filename(buf); 10485 } 10486 else if (buf[0] == NUL) 10487 /* relative to current directory */ 10488 STRCPY(buf, curdir); 10489 else if (path_with_url(buf)) 10490 /* URL can't be used here */ 10491 continue; 10492 else if (!mch_isFullName(buf)) 10493 { 10494 /* Expand relative path to their full path equivalent */ 10495 len = (int)STRLEN(curdir); 10496 if (len + (int)STRLEN(buf) + 3 > MAXPATHL) 10497 continue; 10498 STRMOVE(buf + len + 1, buf); 10499 STRCPY(buf, curdir); 10500 buf[len] = PATHSEP; 10501 simplify_filename(buf); 10502 } 10503 10504 if (ga_grow(gap, 1) == FAIL) 10505 break; 10506 10507 # if defined(MSWIN) 10508 /* Avoid the path ending in a backslash, it fails when a comma is 10509 * appended. */ 10510 len = (int)STRLEN(buf); 10511 if (buf[len - 1] == '\\') 10512 buf[len - 1] = '/'; 10513 # endif 10514 10515 p = vim_strsave(buf); 10516 if (p == NULL) 10517 break; 10518 ((char_u **)gap->ga_data)[gap->ga_len++] = p; 10519 } 10520 10521 vim_free(buf); 10522 } 10523 10524 /* 10525 * Returns a pointer to the file or directory name in "fname" that matches the 10526 * longest path in "ga"p, or NULL if there is no match. For example: 10527 * 10528 * path: /foo/bar/baz 10529 * fname: /foo/bar/baz/quux.txt 10530 * returns: ^this 10531 */ 10532 static char_u * 10533 get_path_cutoff(char_u *fname, garray_T *gap) 10534 { 10535 int i; 10536 int maxlen = 0; 10537 char_u **path_part = (char_u **)gap->ga_data; 10538 char_u *cutoff = NULL; 10539 10540 for (i = 0; i < gap->ga_len; i++) 10541 { 10542 int j = 0; 10543 10544 while ((fname[j] == path_part[i][j] 10545 # if defined(MSWIN) 10546 || (vim_ispathsep(fname[j]) && vim_ispathsep(path_part[i][j])) 10547 #endif 10548 ) && fname[j] != NUL && path_part[i][j] != NUL) 10549 j++; 10550 if (j > maxlen) 10551 { 10552 maxlen = j; 10553 cutoff = &fname[j]; 10554 } 10555 } 10556 10557 /* skip to the file or directory name */ 10558 if (cutoff != NULL) 10559 while (vim_ispathsep(*cutoff)) 10560 MB_PTR_ADV(cutoff); 10561 10562 return cutoff; 10563 } 10564 10565 /* 10566 * Sorts, removes duplicates and modifies all the fullpath names in "gap" so 10567 * that they are unique with respect to each other while conserving the part 10568 * that matches the pattern. Beware, this is at least O(n^2) wrt "gap->ga_len". 10569 */ 10570 static void 10571 uniquefy_paths(garray_T *gap, char_u *pattern) 10572 { 10573 int i; 10574 int len; 10575 char_u **fnames = (char_u **)gap->ga_data; 10576 int sort_again = FALSE; 10577 char_u *pat; 10578 char_u *file_pattern; 10579 char_u *curdir; 10580 regmatch_T regmatch; 10581 garray_T path_ga; 10582 char_u **in_curdir = NULL; 10583 char_u *short_name; 10584 10585 remove_duplicates(gap); 10586 ga_init2(&path_ga, (int)sizeof(char_u *), 1); 10587 10588 /* 10589 * We need to prepend a '*' at the beginning of file_pattern so that the 10590 * regex matches anywhere in the path. FIXME: is this valid for all 10591 * possible patterns? 10592 */ 10593 len = (int)STRLEN(pattern); 10594 file_pattern = alloc(len + 2); 10595 if (file_pattern == NULL) 10596 return; 10597 file_pattern[0] = '*'; 10598 file_pattern[1] = NUL; 10599 STRCAT(file_pattern, pattern); 10600 pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, TRUE); 10601 vim_free(file_pattern); 10602 if (pat == NULL) 10603 return; 10604 10605 regmatch.rm_ic = TRUE; /* always ignore case */ 10606 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); 10607 vim_free(pat); 10608 if (regmatch.regprog == NULL) 10609 return; 10610 10611 if ((curdir = alloc((int)(MAXPATHL))) == NULL) 10612 goto theend; 10613 mch_dirname(curdir, MAXPATHL); 10614 expand_path_option(curdir, &path_ga); 10615 10616 in_curdir = (char_u **)alloc_clear(gap->ga_len * sizeof(char_u *)); 10617 if (in_curdir == NULL) 10618 goto theend; 10619 10620 for (i = 0; i < gap->ga_len && !got_int; i++) 10621 { 10622 char_u *path = fnames[i]; 10623 int is_in_curdir; 10624 char_u *dir_end = gettail_dir(path); 10625 char_u *pathsep_p; 10626 char_u *path_cutoff; 10627 10628 len = (int)STRLEN(path); 10629 is_in_curdir = fnamencmp(curdir, path, dir_end - path) == 0 10630 && curdir[dir_end - path] == NUL; 10631 if (is_in_curdir) 10632 in_curdir[i] = vim_strsave(path); 10633 10634 /* Shorten the filename while maintaining its uniqueness */ 10635 path_cutoff = get_path_cutoff(path, &path_ga); 10636 10637 /* Don't assume all files can be reached without path when search 10638 * pattern starts with star star slash, so only remove path_cutoff 10639 * when possible. */ 10640 if (pattern[0] == '*' && pattern[1] == '*' 10641 && vim_ispathsep_nocolon(pattern[2]) 10642 && path_cutoff != NULL 10643 && vim_regexec(®match, path_cutoff, (colnr_T)0) 10644 && is_unique(path_cutoff, gap, i)) 10645 { 10646 sort_again = TRUE; 10647 mch_memmove(path, path_cutoff, STRLEN(path_cutoff) + 1); 10648 } 10649 else 10650 { 10651 /* Here all files can be reached without path, so get shortest 10652 * unique path. We start at the end of the path. */ 10653 pathsep_p = path + len - 1; 10654 10655 while (find_previous_pathsep(path, &pathsep_p)) 10656 if (vim_regexec(®match, pathsep_p + 1, (colnr_T)0) 10657 && is_unique(pathsep_p + 1, gap, i) 10658 && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff) 10659 { 10660 sort_again = TRUE; 10661 mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p)); 10662 break; 10663 } 10664 } 10665 10666 if (mch_isFullName(path)) 10667 { 10668 /* 10669 * Last resort: shorten relative to curdir if possible. 10670 * 'possible' means: 10671 * 1. It is under the current directory. 10672 * 2. The result is actually shorter than the original. 10673 * 10674 * Before curdir After 10675 * /foo/bar/file.txt /foo/bar ./file.txt 10676 * c:\foo\bar\file.txt c:\foo\bar .\file.txt 10677 * /file.txt / /file.txt 10678 * c:\file.txt c:\ .\file.txt 10679 */ 10680 short_name = shorten_fname(path, curdir); 10681 if (short_name != NULL && short_name > path + 1 10682 #if defined(MSWIN) 10683 /* On windows, 10684 * shorten_fname("c:\a\a.txt", "c:\a\b") 10685 * returns "\a\a.txt", which is not really the short 10686 * name, hence: */ 10687 && !vim_ispathsep(*short_name) 10688 #endif 10689 ) 10690 { 10691 STRCPY(path, "."); 10692 add_pathsep(path); 10693 STRMOVE(path + STRLEN(path), short_name); 10694 } 10695 } 10696 ui_breakcheck(); 10697 } 10698 10699 /* Shorten filenames in /in/current/directory/{filename} */ 10700 for (i = 0; i < gap->ga_len && !got_int; i++) 10701 { 10702 char_u *rel_path; 10703 char_u *path = in_curdir[i]; 10704 10705 if (path == NULL) 10706 continue; 10707 10708 /* If the {filename} is not unique, change it to ./{filename}. 10709 * Else reduce it to {filename} */ 10710 short_name = shorten_fname(path, curdir); 10711 if (short_name == NULL) 10712 short_name = path; 10713 if (is_unique(short_name, gap, i)) 10714 { 10715 STRCPY(fnames[i], short_name); 10716 continue; 10717 } 10718 10719 rel_path = alloc((int)(STRLEN(short_name) + STRLEN(PATHSEPSTR) + 2)); 10720 if (rel_path == NULL) 10721 goto theend; 10722 STRCPY(rel_path, "."); 10723 add_pathsep(rel_path); 10724 STRCAT(rel_path, short_name); 10725 10726 vim_free(fnames[i]); 10727 fnames[i] = rel_path; 10728 sort_again = TRUE; 10729 ui_breakcheck(); 10730 } 10731 10732 theend: 10733 vim_free(curdir); 10734 if (in_curdir != NULL) 10735 { 10736 for (i = 0; i < gap->ga_len; i++) 10737 vim_free(in_curdir[i]); 10738 vim_free(in_curdir); 10739 } 10740 ga_clear_strings(&path_ga); 10741 vim_regfree(regmatch.regprog); 10742 10743 if (sort_again) 10744 remove_duplicates(gap); 10745 } 10746 10747 /* 10748 * Calls globpath() with 'path' values for the given pattern and stores the 10749 * result in "gap". 10750 * Returns the total number of matches. 10751 */ 10752 static int 10753 expand_in_path( 10754 garray_T *gap, 10755 char_u *pattern, 10756 int flags) /* EW_* flags */ 10757 { 10758 char_u *curdir; 10759 garray_T path_ga; 10760 char_u *paths = NULL; 10761 10762 if ((curdir = alloc((unsigned)MAXPATHL)) == NULL) 10763 return 0; 10764 mch_dirname(curdir, MAXPATHL); 10765 10766 ga_init2(&path_ga, (int)sizeof(char_u *), 1); 10767 expand_path_option(curdir, &path_ga); 10768 vim_free(curdir); 10769 if (path_ga.ga_len == 0) 10770 return 0; 10771 10772 paths = ga_concat_strings(&path_ga, ","); 10773 ga_clear_strings(&path_ga); 10774 if (paths == NULL) 10775 return 0; 10776 10777 globpath(paths, pattern, gap, (flags & EW_ICASE) ? WILD_ICASE : 0); 10778 vim_free(paths); 10779 10780 return gap->ga_len; 10781 } 10782 #endif 10783 10784 #if defined(FEAT_SEARCHPATH) || defined(FEAT_CMDL_COMPL) || defined(PROTO) 10785 /* 10786 * Sort "gap" and remove duplicate entries. "gap" is expected to contain a 10787 * list of file names in allocated memory. 10788 */ 10789 void 10790 remove_duplicates(garray_T *gap) 10791 { 10792 int i; 10793 int j; 10794 char_u **fnames = (char_u **)gap->ga_data; 10795 10796 sort_strings(fnames, gap->ga_len); 10797 for (i = gap->ga_len - 1; i > 0; --i) 10798 if (fnamecmp(fnames[i - 1], fnames[i]) == 0) 10799 { 10800 vim_free(fnames[i]); 10801 for (j = i + 1; j < gap->ga_len; ++j) 10802 fnames[j - 1] = fnames[j]; 10803 --gap->ga_len; 10804 } 10805 } 10806 #endif 10807 10808 static int has_env_var(char_u *p); 10809 10810 /* 10811 * Return TRUE if "p" contains what looks like an environment variable. 10812 * Allowing for escaping. 10813 */ 10814 static int 10815 has_env_var(char_u *p) 10816 { 10817 for ( ; *p; MB_PTR_ADV(p)) 10818 { 10819 if (*p == '\\' && p[1] != NUL) 10820 ++p; 10821 else if (vim_strchr((char_u *) 10822 #if defined(MSWIN) 10823 "$%" 10824 #else 10825 "$" 10826 #endif 10827 , *p) != NULL) 10828 return TRUE; 10829 } 10830 return FALSE; 10831 } 10832 10833 #ifdef SPECIAL_WILDCHAR 10834 static int has_special_wildchar(char_u *p); 10835 10836 /* 10837 * Return TRUE if "p" contains a special wildcard character, one that Vim 10838 * cannot expand, requires using a shell. 10839 */ 10840 static int 10841 has_special_wildchar(char_u *p) 10842 { 10843 for ( ; *p; MB_PTR_ADV(p)) 10844 { 10845 /* Allow for escaping. */ 10846 if (*p == '\\' && p[1] != NUL) 10847 ++p; 10848 else if (vim_strchr((char_u *)SPECIAL_WILDCHAR, *p) != NULL) 10849 return TRUE; 10850 } 10851 return FALSE; 10852 } 10853 #endif 10854 10855 /* 10856 * Generic wildcard expansion code. 10857 * 10858 * Characters in "pat" that should not be expanded must be preceded with a 10859 * backslash. E.g., "/path\ with\ spaces/my\*star*" 10860 * 10861 * Return FAIL when no single file was found. In this case "num_file" is not 10862 * set, and "file" may contain an error message. 10863 * Return OK when some files found. "num_file" is set to the number of 10864 * matches, "file" to the array of matches. Call FreeWild() later. 10865 */ 10866 int 10867 gen_expand_wildcards( 10868 int num_pat, /* number of input patterns */ 10869 char_u **pat, /* array of input patterns */ 10870 int *num_file, /* resulting number of files */ 10871 char_u ***file, /* array of resulting files */ 10872 int flags) /* EW_* flags */ 10873 { 10874 int i; 10875 garray_T ga; 10876 char_u *p; 10877 static int recursive = FALSE; 10878 int add_pat; 10879 int retval = OK; 10880 #if defined(FEAT_SEARCHPATH) 10881 int did_expand_in_path = FALSE; 10882 #endif 10883 10884 /* 10885 * expand_env() is called to expand things like "~user". If this fails, 10886 * it calls ExpandOne(), which brings us back here. In this case, always 10887 * call the machine specific expansion function, if possible. Otherwise, 10888 * return FAIL. 10889 */ 10890 if (recursive) 10891 #ifdef SPECIAL_WILDCHAR 10892 return mch_expand_wildcards(num_pat, pat, num_file, file, flags); 10893 #else 10894 return FAIL; 10895 #endif 10896 10897 #ifdef SPECIAL_WILDCHAR 10898 /* 10899 * If there are any special wildcard characters which we cannot handle 10900 * here, call machine specific function for all the expansion. This 10901 * avoids starting the shell for each argument separately. 10902 * For `=expr` do use the internal function. 10903 */ 10904 for (i = 0; i < num_pat; i++) 10905 { 10906 if (has_special_wildchar(pat[i]) 10907 # ifdef VIM_BACKTICK 10908 && !(vim_backtick(pat[i]) && pat[i][1] == '=') 10909 # endif 10910 ) 10911 return mch_expand_wildcards(num_pat, pat, num_file, file, flags); 10912 } 10913 #endif 10914 10915 recursive = TRUE; 10916 10917 /* 10918 * The matching file names are stored in a growarray. Init it empty. 10919 */ 10920 ga_init2(&ga, (int)sizeof(char_u *), 30); 10921 10922 for (i = 0; i < num_pat; ++i) 10923 { 10924 add_pat = -1; 10925 p = pat[i]; 10926 10927 #ifdef VIM_BACKTICK 10928 if (vim_backtick(p)) 10929 { 10930 add_pat = expand_backtick(&ga, p, flags); 10931 if (add_pat == -1) 10932 retval = FAIL; 10933 } 10934 else 10935 #endif 10936 { 10937 /* 10938 * First expand environment variables, "~/" and "~user/". 10939 */ 10940 if (has_env_var(p) || *p == '~') 10941 { 10942 p = expand_env_save_opt(p, TRUE); 10943 if (p == NULL) 10944 p = pat[i]; 10945 #ifdef UNIX 10946 /* 10947 * On Unix, if expand_env() can't expand an environment 10948 * variable, use the shell to do that. Discard previously 10949 * found file names and start all over again. 10950 */ 10951 else if (has_env_var(p) || *p == '~') 10952 { 10953 vim_free(p); 10954 ga_clear_strings(&ga); 10955 i = mch_expand_wildcards(num_pat, pat, num_file, file, 10956 flags|EW_KEEPDOLLAR); 10957 recursive = FALSE; 10958 return i; 10959 } 10960 #endif 10961 } 10962 10963 /* 10964 * If there are wildcards: Expand file names and add each match to 10965 * the list. If there is no match, and EW_NOTFOUND is given, add 10966 * the pattern. 10967 * If there are no wildcards: Add the file name if it exists or 10968 * when EW_NOTFOUND is given. 10969 */ 10970 if (mch_has_exp_wildcard(p)) 10971 { 10972 #if defined(FEAT_SEARCHPATH) 10973 if ((flags & EW_PATH) 10974 && !mch_isFullName(p) 10975 && !(p[0] == '.' 10976 && (vim_ispathsep(p[1]) 10977 || (p[1] == '.' && vim_ispathsep(p[2])))) 10978 ) 10979 { 10980 /* :find completion where 'path' is used. 10981 * Recursiveness is OK here. */ 10982 recursive = FALSE; 10983 add_pat = expand_in_path(&ga, p, flags); 10984 recursive = TRUE; 10985 did_expand_in_path = TRUE; 10986 } 10987 else 10988 #endif 10989 add_pat = mch_expandpath(&ga, p, flags); 10990 } 10991 } 10992 10993 if (add_pat == -1 || (add_pat == 0 && (flags & EW_NOTFOUND))) 10994 { 10995 char_u *t = backslash_halve_save(p); 10996 10997 #if defined(MACOS_CLASSIC) 10998 slash_to_colon(t); 10999 #endif 11000 /* When EW_NOTFOUND is used, always add files and dirs. Makes 11001 * "vim c:/" work. */ 11002 if (flags & EW_NOTFOUND) 11003 addfile(&ga, t, flags | EW_DIR | EW_FILE); 11004 else 11005 addfile(&ga, t, flags); 11006 vim_free(t); 11007 } 11008 11009 #if defined(FEAT_SEARCHPATH) 11010 if (did_expand_in_path && ga.ga_len > 0 && (flags & EW_PATH)) 11011 uniquefy_paths(&ga, p); 11012 #endif 11013 if (p != pat[i]) 11014 vim_free(p); 11015 } 11016 11017 *num_file = ga.ga_len; 11018 *file = (ga.ga_data != NULL) ? (char_u **)ga.ga_data : (char_u **)""; 11019 11020 recursive = FALSE; 11021 11022 return ((flags & EW_EMPTYOK) || ga.ga_data != NULL) ? retval : FAIL; 11023 } 11024 11025 # ifdef VIM_BACKTICK 11026 11027 /* 11028 * Return TRUE if we can expand this backtick thing here. 11029 */ 11030 static int 11031 vim_backtick(char_u *p) 11032 { 11033 return (*p == '`' && *(p + 1) != NUL && *(p + STRLEN(p) - 1) == '`'); 11034 } 11035 11036 /* 11037 * Expand an item in `backticks` by executing it as a command. 11038 * Currently only works when pat[] starts and ends with a `. 11039 * Returns number of file names found, -1 if an error is encountered. 11040 */ 11041 static int 11042 expand_backtick( 11043 garray_T *gap, 11044 char_u *pat, 11045 int flags) /* EW_* flags */ 11046 { 11047 char_u *p; 11048 char_u *cmd; 11049 char_u *buffer; 11050 int cnt = 0; 11051 int i; 11052 11053 /* Create the command: lop off the backticks. */ 11054 cmd = vim_strnsave(pat + 1, (int)STRLEN(pat) - 2); 11055 if (cmd == NULL) 11056 return -1; 11057 11058 #ifdef FEAT_EVAL 11059 if (*cmd == '=') /* `={expr}`: Expand expression */ 11060 buffer = eval_to_string(cmd + 1, &p, TRUE); 11061 else 11062 #endif 11063 buffer = get_cmd_output(cmd, NULL, 11064 (flags & EW_SILENT) ? SHELL_SILENT : 0, NULL); 11065 vim_free(cmd); 11066 if (buffer == NULL) 11067 return -1; 11068 11069 cmd = buffer; 11070 while (*cmd != NUL) 11071 { 11072 cmd = skipwhite(cmd); /* skip over white space */ 11073 p = cmd; 11074 while (*p != NUL && *p != '\r' && *p != '\n') /* skip over entry */ 11075 ++p; 11076 /* add an entry if it is not empty */ 11077 if (p > cmd) 11078 { 11079 i = *p; 11080 *p = NUL; 11081 addfile(gap, cmd, flags); 11082 *p = i; 11083 ++cnt; 11084 } 11085 cmd = p; 11086 while (*cmd != NUL && (*cmd == '\r' || *cmd == '\n')) 11087 ++cmd; 11088 } 11089 11090 vim_free(buffer); 11091 return cnt; 11092 } 11093 # endif /* VIM_BACKTICK */ 11094 11095 /* 11096 * Add a file to a file list. Accepted flags: 11097 * EW_DIR add directories 11098 * EW_FILE add files 11099 * EW_EXEC add executable files 11100 * EW_NOTFOUND add even when it doesn't exist 11101 * EW_ADDSLASH add slash after directory name 11102 * EW_ALLLINKS add symlink also when the referred file does not exist 11103 */ 11104 void 11105 addfile( 11106 garray_T *gap, 11107 char_u *f, /* filename */ 11108 int flags) 11109 { 11110 char_u *p; 11111 int isdir; 11112 stat_T sb; 11113 11114 /* if the file/dir/link doesn't exist, may not add it */ 11115 if (!(flags & EW_NOTFOUND) && ((flags & EW_ALLLINKS) 11116 ? mch_lstat((char *)f, &sb) < 0 : mch_getperm(f) < 0)) 11117 return; 11118 11119 #ifdef FNAME_ILLEGAL 11120 /* if the file/dir contains illegal characters, don't add it */ 11121 if (vim_strpbrk(f, (char_u *)FNAME_ILLEGAL) != NULL) 11122 return; 11123 #endif 11124 11125 isdir = mch_isdir(f); 11126 if ((isdir && !(flags & EW_DIR)) || (!isdir && !(flags & EW_FILE))) 11127 return; 11128 11129 /* If the file isn't executable, may not add it. Do accept directories. 11130 * When invoked from expand_shellcmd() do not use $PATH. */ 11131 if (!isdir && (flags & EW_EXEC) 11132 && !mch_can_exe(f, NULL, !(flags & EW_SHELLCMD))) 11133 return; 11134 11135 /* Make room for another item in the file list. */ 11136 if (ga_grow(gap, 1) == FAIL) 11137 return; 11138 11139 p = alloc((unsigned)(STRLEN(f) + 1 + isdir)); 11140 if (p == NULL) 11141 return; 11142 11143 STRCPY(p, f); 11144 #ifdef BACKSLASH_IN_FILENAME 11145 slash_adjust(p); 11146 #endif 11147 /* 11148 * Append a slash or backslash after directory names if none is present. 11149 */ 11150 #ifndef DONT_ADD_PATHSEP_TO_DIR 11151 if (isdir && (flags & EW_ADDSLASH)) 11152 add_pathsep(p); 11153 #endif 11154 ((char_u **)gap->ga_data)[gap->ga_len++] = p; 11155 } 11156 #endif /* !NO_EXPANDPATH */ 11157 11158 #if defined(VIM_BACKTICK) || defined(FEAT_EVAL) || defined(PROTO) 11159 11160 #ifndef SEEK_SET 11161 # define SEEK_SET 0 11162 #endif 11163 #ifndef SEEK_END 11164 # define SEEK_END 2 11165 #endif 11166 11167 /* 11168 * Get the stdout of an external command. 11169 * If "ret_len" is NULL replace NUL characters with NL. When "ret_len" is not 11170 * NULL store the length there. 11171 * Returns an allocated string, or NULL for error. 11172 */ 11173 char_u * 11174 get_cmd_output( 11175 char_u *cmd, 11176 char_u *infile, /* optional input file name */ 11177 int flags, /* can be SHELL_SILENT */ 11178 int *ret_len) 11179 { 11180 char_u *tempname; 11181 char_u *command; 11182 char_u *buffer = NULL; 11183 int len; 11184 int i = 0; 11185 FILE *fd; 11186 11187 if (check_restricted() || check_secure()) 11188 return NULL; 11189 11190 /* get a name for the temp file */ 11191 if ((tempname = vim_tempname('o', FALSE)) == NULL) 11192 { 11193 EMSG(_(e_notmp)); 11194 return NULL; 11195 } 11196 11197 /* Add the redirection stuff */ 11198 command = make_filter_cmd(cmd, infile, tempname); 11199 if (command == NULL) 11200 goto done; 11201 11202 /* 11203 * Call the shell to execute the command (errors are ignored). 11204 * Don't check timestamps here. 11205 */ 11206 ++no_check_timestamps; 11207 call_shell(command, SHELL_DOOUT | SHELL_EXPAND | flags); 11208 --no_check_timestamps; 11209 11210 vim_free(command); 11211 11212 /* 11213 * read the names from the file into memory 11214 */ 11215 # ifdef VMS 11216 /* created temporary file is not always readable as binary */ 11217 fd = mch_fopen((char *)tempname, "r"); 11218 # else 11219 fd = mch_fopen((char *)tempname, READBIN); 11220 # endif 11221 11222 if (fd == NULL) 11223 { 11224 EMSG2(_(e_notopen), tempname); 11225 goto done; 11226 } 11227 11228 fseek(fd, 0L, SEEK_END); 11229 len = ftell(fd); /* get size of temp file */ 11230 fseek(fd, 0L, SEEK_SET); 11231 11232 buffer = alloc(len + 1); 11233 if (buffer != NULL) 11234 i = (int)fread((char *)buffer, (size_t)1, (size_t)len, fd); 11235 fclose(fd); 11236 mch_remove(tempname); 11237 if (buffer == NULL) 11238 goto done; 11239 #ifdef VMS 11240 len = i; /* VMS doesn't give us what we asked for... */ 11241 #endif 11242 if (i != len) 11243 { 11244 EMSG2(_(e_notread), tempname); 11245 vim_free(buffer); 11246 buffer = NULL; 11247 } 11248 else if (ret_len == NULL) 11249 { 11250 /* Change NUL into SOH, otherwise the string is truncated. */ 11251 for (i = 0; i < len; ++i) 11252 if (buffer[i] == NUL) 11253 buffer[i] = 1; 11254 11255 buffer[len] = NUL; /* make sure the buffer is terminated */ 11256 } 11257 else 11258 *ret_len = len; 11259 11260 done: 11261 vim_free(tempname); 11262 return buffer; 11263 } 11264 #endif 11265 11266 /* 11267 * Free the list of files returned by expand_wildcards() or other expansion 11268 * functions. 11269 */ 11270 void 11271 FreeWild(int count, char_u **files) 11272 { 11273 if (count <= 0 || files == NULL) 11274 return; 11275 while (count--) 11276 vim_free(files[count]); 11277 vim_free(files); 11278 } 11279 11280 /* 11281 * Return TRUE when need to go to Insert mode because of 'insertmode'. 11282 * Don't do this when still processing a command or a mapping. 11283 * Don't do this when inside a ":normal" command. 11284 */ 11285 int 11286 goto_im(void) 11287 { 11288 return (p_im && stuff_empty() && typebuf_typed()); 11289 } 11290 11291 /* 11292 * Returns the isolated name of the shell in allocated memory: 11293 * - Skip beyond any path. E.g., "/usr/bin/csh -f" -> "csh -f". 11294 * - Remove any argument. E.g., "csh -f" -> "csh". 11295 * But don't allow a space in the path, so that this works: 11296 * "/usr/bin/csh --rcfile ~/.cshrc" 11297 * But don't do that for Windows, it's common to have a space in the path. 11298 */ 11299 char_u * 11300 get_isolated_shell_name(void) 11301 { 11302 char_u *p; 11303 11304 #ifdef WIN3264 11305 p = gettail(p_sh); 11306 p = vim_strnsave(p, (int)(skiptowhite(p) - p)); 11307 #else 11308 p = skiptowhite(p_sh); 11309 if (*p == NUL) 11310 { 11311 /* No white space, use the tail. */ 11312 p = vim_strsave(gettail(p_sh)); 11313 } 11314 else 11315 { 11316 char_u *p1, *p2; 11317 11318 /* Find the last path separator before the space. */ 11319 p1 = p_sh; 11320 for (p2 = p_sh; p2 < p; MB_PTR_ADV(p2)) 11321 if (vim_ispathsep(*p2)) 11322 p1 = p2 + 1; 11323 p = vim_strnsave(p1, (int)(p - p1)); 11324 } 11325 #endif 11326 return p; 11327 } 11328