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 * misc2.c: Various functions. 12 */ 13 #include "vim.h" 14 15 static char_u *username = NULL; /* cached result of mch_get_user_name() */ 16 17 static char_u *ff_expand_buffer = NULL; /* used for expanding filenames */ 18 19 #if defined(FEAT_VIRTUALEDIT) || defined(PROTO) 20 static int coladvance2(pos_T *pos, int addspaces, int finetune, colnr_T wcol); 21 22 /* 23 * Return TRUE if in the current mode we need to use virtual. 24 */ 25 int 26 virtual_active(void) 27 { 28 /* While an operator is being executed we return "virtual_op", because 29 * VIsual_active has already been reset, thus we can't check for "block" 30 * being used. */ 31 if (virtual_op != MAYBE) 32 return virtual_op; 33 return (ve_flags == VE_ALL 34 || ((ve_flags & VE_BLOCK) && VIsual_active && VIsual_mode == Ctrl_V) 35 || ((ve_flags & VE_INSERT) && (State & INSERT))); 36 } 37 38 /* 39 * Get the screen position of the cursor. 40 */ 41 int 42 getviscol(void) 43 { 44 colnr_T x; 45 46 getvvcol(curwin, &curwin->w_cursor, &x, NULL, NULL); 47 return (int)x; 48 } 49 50 /* 51 * Get the screen position of character col with a coladd in the cursor line. 52 */ 53 int 54 getviscol2(colnr_T col, colnr_T coladd) 55 { 56 colnr_T x; 57 pos_T pos; 58 59 pos.lnum = curwin->w_cursor.lnum; 60 pos.col = col; 61 pos.coladd = coladd; 62 getvvcol(curwin, &pos, &x, NULL, NULL); 63 return (int)x; 64 } 65 66 /* 67 * Go to column "wcol", and add/insert white space as necessary to get the 68 * cursor in that column. 69 * The caller must have saved the cursor line for undo! 70 */ 71 int 72 coladvance_force(colnr_T wcol) 73 { 74 int rc = coladvance2(&curwin->w_cursor, TRUE, FALSE, wcol); 75 76 if (wcol == MAXCOL) 77 curwin->w_valid &= ~VALID_VIRTCOL; 78 else 79 { 80 /* Virtcol is valid */ 81 curwin->w_valid |= VALID_VIRTCOL; 82 curwin->w_virtcol = wcol; 83 } 84 return rc; 85 } 86 #endif 87 88 /* 89 * Try to advance the Cursor to the specified screen column. 90 * If virtual editing: fine tune the cursor position. 91 * Note that all virtual positions off the end of a line should share 92 * a curwin->w_cursor.col value (n.b. this is equal to STRLEN(line)), 93 * beginning at coladd 0. 94 * 95 * return OK if desired column is reached, FAIL if not 96 */ 97 int 98 coladvance(colnr_T wcol) 99 { 100 int rc = getvpos(&curwin->w_cursor, wcol); 101 102 if (wcol == MAXCOL || rc == FAIL) 103 curwin->w_valid &= ~VALID_VIRTCOL; 104 else if (*ml_get_cursor() != TAB) 105 { 106 /* Virtcol is valid when not on a TAB */ 107 curwin->w_valid |= VALID_VIRTCOL; 108 curwin->w_virtcol = wcol; 109 } 110 return rc; 111 } 112 113 /* 114 * Return in "pos" the position of the cursor advanced to screen column "wcol". 115 * return OK if desired column is reached, FAIL if not 116 */ 117 int 118 getvpos(pos_T *pos, colnr_T wcol) 119 { 120 #ifdef FEAT_VIRTUALEDIT 121 return coladvance2(pos, FALSE, virtual_active(), wcol); 122 } 123 124 static int 125 coladvance2( 126 pos_T *pos, 127 int addspaces, /* change the text to achieve our goal? */ 128 int finetune, /* change char offset for the exact column */ 129 colnr_T wcol) /* column to move to */ 130 { 131 #endif 132 int idx; 133 char_u *ptr; 134 char_u *line; 135 colnr_T col = 0; 136 int csize = 0; 137 int one_more; 138 #ifdef FEAT_LINEBREAK 139 int head = 0; 140 #endif 141 142 one_more = (State & INSERT) 143 || restart_edit != NUL 144 || (VIsual_active && *p_sel != 'o') 145 #ifdef FEAT_VIRTUALEDIT 146 || ((ve_flags & VE_ONEMORE) && wcol < MAXCOL) 147 #endif 148 ; 149 line = ml_get_buf(curbuf, pos->lnum, FALSE); 150 151 if (wcol >= MAXCOL) 152 { 153 idx = (int)STRLEN(line) - 1 + one_more; 154 col = wcol; 155 156 #ifdef FEAT_VIRTUALEDIT 157 if ((addspaces || finetune) && !VIsual_active) 158 { 159 curwin->w_curswant = linetabsize(line) + one_more; 160 if (curwin->w_curswant > 0) 161 --curwin->w_curswant; 162 } 163 #endif 164 } 165 else 166 { 167 #ifdef FEAT_VIRTUALEDIT 168 int width = curwin->w_width - win_col_off(curwin); 169 170 if (finetune 171 && curwin->w_p_wrap 172 && curwin->w_width != 0 173 && wcol >= (colnr_T)width) 174 { 175 csize = linetabsize(line); 176 if (csize > 0) 177 csize--; 178 179 if (wcol / width > (colnr_T)csize / width 180 && ((State & INSERT) == 0 || (int)wcol > csize + 1)) 181 { 182 /* In case of line wrapping don't move the cursor beyond the 183 * right screen edge. In Insert mode allow going just beyond 184 * the last character (like what happens when typing and 185 * reaching the right window edge). */ 186 wcol = (csize / width + 1) * width - 1; 187 } 188 } 189 #endif 190 191 ptr = line; 192 while (col <= wcol && *ptr != NUL) 193 { 194 /* Count a tab for what it's worth (if list mode not on) */ 195 #ifdef FEAT_LINEBREAK 196 csize = win_lbr_chartabsize(curwin, line, ptr, col, &head); 197 MB_PTR_ADV(ptr); 198 #else 199 csize = lbr_chartabsize_adv(line, &ptr, col); 200 #endif 201 col += csize; 202 } 203 idx = (int)(ptr - line); 204 /* 205 * Handle all the special cases. The virtual_active() check 206 * is needed to ensure that a virtual position off the end of 207 * a line has the correct indexing. The one_more comparison 208 * replaces an explicit add of one_more later on. 209 */ 210 if (col > wcol || (!virtual_active() && one_more == 0)) 211 { 212 idx -= 1; 213 # ifdef FEAT_LINEBREAK 214 /* Don't count the chars from 'showbreak'. */ 215 csize -= head; 216 # endif 217 col -= csize; 218 } 219 220 #ifdef FEAT_VIRTUALEDIT 221 if (virtual_active() 222 && addspaces 223 && ((col != wcol && col != wcol + 1) || csize > 1)) 224 { 225 /* 'virtualedit' is set: The difference between wcol and col is 226 * filled with spaces. */ 227 228 if (line[idx] == NUL) 229 { 230 /* Append spaces */ 231 int correct = wcol - col; 232 char_u *newline = alloc(idx + correct + 1); 233 int t; 234 235 if (newline == NULL) 236 return FAIL; 237 238 for (t = 0; t < idx; ++t) 239 newline[t] = line[t]; 240 241 for (t = 0; t < correct; ++t) 242 newline[t + idx] = ' '; 243 244 newline[idx + correct] = NUL; 245 246 ml_replace(pos->lnum, newline, FALSE); 247 changed_bytes(pos->lnum, (colnr_T)idx); 248 idx += correct; 249 col = wcol; 250 } 251 else 252 { 253 /* Break a tab */ 254 int linelen = (int)STRLEN(line); 255 int correct = wcol - col - csize + 1; /* negative!! */ 256 char_u *newline; 257 int t, s = 0; 258 int v; 259 260 if (-correct > csize) 261 return FAIL; 262 263 newline = alloc(linelen + csize); 264 if (newline == NULL) 265 return FAIL; 266 267 for (t = 0; t < linelen; t++) 268 { 269 if (t != idx) 270 newline[s++] = line[t]; 271 else 272 for (v = 0; v < csize; v++) 273 newline[s++] = ' '; 274 } 275 276 newline[linelen + csize - 1] = NUL; 277 278 ml_replace(pos->lnum, newline, FALSE); 279 changed_bytes(pos->lnum, idx); 280 idx += (csize - 1 + correct); 281 col += correct; 282 } 283 } 284 #endif 285 } 286 287 if (idx < 0) 288 pos->col = 0; 289 else 290 pos->col = idx; 291 292 #ifdef FEAT_VIRTUALEDIT 293 pos->coladd = 0; 294 295 if (finetune) 296 { 297 if (wcol == MAXCOL) 298 { 299 /* The width of the last character is used to set coladd. */ 300 if (!one_more) 301 { 302 colnr_T scol, ecol; 303 304 getvcol(curwin, pos, &scol, NULL, &ecol); 305 pos->coladd = ecol - scol; 306 } 307 } 308 else 309 { 310 int b = (int)wcol - (int)col; 311 312 /* The difference between wcol and col is used to set coladd. */ 313 if (b > 0 && b < (MAXCOL - 2 * curwin->w_width)) 314 pos->coladd = b; 315 316 col += b; 317 } 318 } 319 #endif 320 321 #ifdef FEAT_MBYTE 322 /* prevent from moving onto a trail byte */ 323 if (has_mbyte) 324 mb_adjustpos(curbuf, pos); 325 #endif 326 327 if (col < wcol) 328 return FAIL; 329 return OK; 330 } 331 332 /* 333 * Increment the cursor position. See inc() for return values. 334 */ 335 int 336 inc_cursor(void) 337 { 338 return inc(&curwin->w_cursor); 339 } 340 341 /* 342 * Increment the line pointer "lp" crossing line boundaries as necessary. 343 * Return 1 when going to the next line. 344 * Return 2 when moving forward onto a NUL at the end of the line). 345 * Return -1 when at the end of file. 346 * Return 0 otherwise. 347 */ 348 int 349 inc(pos_T *lp) 350 { 351 char_u *p; 352 353 /* when searching position may be set to end of a line */ 354 if (lp->col != MAXCOL) 355 { 356 p = ml_get_pos(lp); 357 if (*p != NUL) /* still within line, move to next char (may be NUL) */ 358 { 359 #ifdef FEAT_MBYTE 360 if (has_mbyte) 361 { 362 int l = (*mb_ptr2len)(p); 363 364 lp->col += l; 365 return ((p[l] != NUL) ? 0 : 2); 366 } 367 #endif 368 lp->col++; 369 #ifdef FEAT_VIRTUALEDIT 370 lp->coladd = 0; 371 #endif 372 return ((p[1] != NUL) ? 0 : 2); 373 } 374 } 375 if (lp->lnum != curbuf->b_ml.ml_line_count) /* there is a next line */ 376 { 377 lp->col = 0; 378 lp->lnum++; 379 #ifdef FEAT_VIRTUALEDIT 380 lp->coladd = 0; 381 #endif 382 return 1; 383 } 384 return -1; 385 } 386 387 /* 388 * incl(lp): same as inc(), but skip the NUL at the end of non-empty lines 389 */ 390 int 391 incl(pos_T *lp) 392 { 393 int r; 394 395 if ((r = inc(lp)) >= 1 && lp->col) 396 r = inc(lp); 397 return r; 398 } 399 400 /* 401 * dec(p) 402 * 403 * Decrement the line pointer 'p' crossing line boundaries as necessary. 404 * Return 1 when crossing a line, -1 when at start of file, 0 otherwise. 405 */ 406 int 407 dec_cursor(void) 408 { 409 return dec(&curwin->w_cursor); 410 } 411 412 int 413 dec(pos_T *lp) 414 { 415 char_u *p; 416 417 #ifdef FEAT_VIRTUALEDIT 418 lp->coladd = 0; 419 #endif 420 if (lp->col == MAXCOL) 421 { 422 /* past end of line */ 423 p = ml_get(lp->lnum); 424 lp->col = (colnr_T)STRLEN(p); 425 #ifdef FEAT_MBYTE 426 if (has_mbyte) 427 lp->col -= (*mb_head_off)(p, p + lp->col); 428 #endif 429 return 0; 430 } 431 432 if (lp->col > 0) 433 { 434 /* still within line */ 435 lp->col--; 436 #ifdef FEAT_MBYTE 437 if (has_mbyte) 438 { 439 p = ml_get(lp->lnum); 440 lp->col -= (*mb_head_off)(p, p + lp->col); 441 } 442 #endif 443 return 0; 444 } 445 446 if (lp->lnum > 1) 447 { 448 /* there is a prior line */ 449 lp->lnum--; 450 p = ml_get(lp->lnum); 451 lp->col = (colnr_T)STRLEN(p); 452 #ifdef FEAT_MBYTE 453 if (has_mbyte) 454 lp->col -= (*mb_head_off)(p, p + lp->col); 455 #endif 456 return 1; 457 } 458 459 /* at start of file */ 460 return -1; 461 } 462 463 /* 464 * decl(lp): same as dec(), but skip the NUL at the end of non-empty lines 465 */ 466 int 467 decl(pos_T *lp) 468 { 469 int r; 470 471 if ((r = dec(lp)) == 1 && lp->col) 472 r = dec(lp); 473 return r; 474 } 475 476 /* 477 * Get the line number relative to the current cursor position, i.e. the 478 * difference between line number and cursor position. Only look for lines that 479 * can be visible, folded lines don't count. 480 */ 481 linenr_T 482 get_cursor_rel_lnum( 483 win_T *wp, 484 linenr_T lnum) /* line number to get the result for */ 485 { 486 linenr_T cursor = wp->w_cursor.lnum; 487 linenr_T retval = 0; 488 489 #ifdef FEAT_FOLDING 490 if (hasAnyFolding(wp)) 491 { 492 if (lnum > cursor) 493 { 494 while (lnum > cursor) 495 { 496 (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL); 497 /* if lnum and cursor are in the same fold, 498 * now lnum <= cursor */ 499 if (lnum > cursor) 500 retval++; 501 lnum--; 502 } 503 } 504 else if (lnum < cursor) 505 { 506 while (lnum < cursor) 507 { 508 (void)hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL); 509 /* if lnum and cursor are in the same fold, 510 * now lnum >= cursor */ 511 if (lnum < cursor) 512 retval--; 513 lnum++; 514 } 515 } 516 /* else if (lnum == cursor) 517 * retval = 0; 518 */ 519 } 520 else 521 #endif 522 retval = lnum - cursor; 523 524 return retval; 525 } 526 527 /* 528 * Make sure "pos.lnum" and "pos.col" are valid in "buf". 529 * This allows for the col to be on the NUL byte. 530 */ 531 void 532 check_pos(buf_T *buf, pos_T *pos) 533 { 534 char_u *line; 535 colnr_T len; 536 537 if (pos->lnum > buf->b_ml.ml_line_count) 538 pos->lnum = buf->b_ml.ml_line_count; 539 540 if (pos->col > 0) 541 { 542 line = ml_get_buf(buf, pos->lnum, FALSE); 543 len = (colnr_T)STRLEN(line); 544 if (pos->col > len) 545 pos->col = len; 546 } 547 } 548 549 /* 550 * Make sure curwin->w_cursor.lnum is valid. 551 */ 552 void 553 check_cursor_lnum(void) 554 { 555 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) 556 { 557 #ifdef FEAT_FOLDING 558 /* If there is a closed fold at the end of the file, put the cursor in 559 * its first line. Otherwise in the last line. */ 560 if (!hasFolding(curbuf->b_ml.ml_line_count, 561 &curwin->w_cursor.lnum, NULL)) 562 #endif 563 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 564 } 565 if (curwin->w_cursor.lnum <= 0) 566 curwin->w_cursor.lnum = 1; 567 } 568 569 /* 570 * Make sure curwin->w_cursor.col is valid. 571 */ 572 void 573 check_cursor_col(void) 574 { 575 check_cursor_col_win(curwin); 576 } 577 578 /* 579 * Make sure win->w_cursor.col is valid. 580 */ 581 void 582 check_cursor_col_win(win_T *win) 583 { 584 colnr_T len; 585 #ifdef FEAT_VIRTUALEDIT 586 colnr_T oldcol = win->w_cursor.col; 587 colnr_T oldcoladd = win->w_cursor.col + win->w_cursor.coladd; 588 #endif 589 590 len = (colnr_T)STRLEN(ml_get_buf(win->w_buffer, win->w_cursor.lnum, FALSE)); 591 if (len == 0) 592 win->w_cursor.col = 0; 593 else if (win->w_cursor.col >= len) 594 { 595 /* Allow cursor past end-of-line when: 596 * - in Insert mode or restarting Insert mode 597 * - in Visual mode and 'selection' isn't "old" 598 * - 'virtualedit' is set */ 599 if ((State & INSERT) || restart_edit 600 || (VIsual_active && *p_sel != 'o') 601 #ifdef FEAT_VIRTUALEDIT 602 || (ve_flags & VE_ONEMORE) 603 #endif 604 || virtual_active()) 605 win->w_cursor.col = len; 606 else 607 { 608 win->w_cursor.col = len - 1; 609 #ifdef FEAT_MBYTE 610 /* Move the cursor to the head byte. */ 611 if (has_mbyte) 612 mb_adjustpos(win->w_buffer, &win->w_cursor); 613 #endif 614 } 615 } 616 else if (win->w_cursor.col < 0) 617 win->w_cursor.col = 0; 618 619 #ifdef FEAT_VIRTUALEDIT 620 /* If virtual editing is on, we can leave the cursor on the old position, 621 * only we must set it to virtual. But don't do it when at the end of the 622 * line. */ 623 if (oldcol == MAXCOL) 624 win->w_cursor.coladd = 0; 625 else if (ve_flags == VE_ALL) 626 { 627 if (oldcoladd > win->w_cursor.col) 628 { 629 win->w_cursor.coladd = oldcoladd - win->w_cursor.col; 630 631 /* Make sure that coladd is not more than the char width. 632 * Not for the last character, coladd is then used when the cursor 633 * is actually after the last character. */ 634 if (win->w_cursor.col + 1 < len && win->w_cursor.coladd > 0) 635 { 636 int cs, ce; 637 638 getvcol(win, &win->w_cursor, &cs, NULL, &ce); 639 if (win->w_cursor.coladd > ce - cs) 640 win->w_cursor.coladd = ce - cs; 641 } 642 } 643 else 644 /* avoid weird number when there is a miscalculation or overflow */ 645 win->w_cursor.coladd = 0; 646 } 647 #endif 648 } 649 650 /* 651 * make sure curwin->w_cursor in on a valid character 652 */ 653 void 654 check_cursor(void) 655 { 656 check_cursor_lnum(); 657 check_cursor_col(); 658 } 659 660 #if defined(FEAT_TEXTOBJ) || defined(PROTO) 661 /* 662 * Make sure curwin->w_cursor is not on the NUL at the end of the line. 663 * Allow it when in Visual mode and 'selection' is not "old". 664 */ 665 void 666 adjust_cursor_col(void) 667 { 668 if (curwin->w_cursor.col > 0 669 && (!VIsual_active || *p_sel == 'o') 670 && gchar_cursor() == NUL) 671 --curwin->w_cursor.col; 672 } 673 #endif 674 675 /* 676 * When curwin->w_leftcol has changed, adjust the cursor position. 677 * Return TRUE if the cursor was moved. 678 */ 679 int 680 leftcol_changed(void) 681 { 682 long lastcol; 683 colnr_T s, e; 684 int retval = FALSE; 685 686 changed_cline_bef_curs(); 687 lastcol = curwin->w_leftcol + curwin->w_width - curwin_col_off() - 1; 688 validate_virtcol(); 689 690 /* 691 * If the cursor is right or left of the screen, move it to last or first 692 * character. 693 */ 694 if (curwin->w_virtcol > (colnr_T)(lastcol - p_siso)) 695 { 696 retval = TRUE; 697 coladvance((colnr_T)(lastcol - p_siso)); 698 } 699 else if (curwin->w_virtcol < curwin->w_leftcol + p_siso) 700 { 701 retval = TRUE; 702 (void)coladvance((colnr_T)(curwin->w_leftcol + p_siso)); 703 } 704 705 /* 706 * If the start of the character under the cursor is not on the screen, 707 * advance the cursor one more char. If this fails (last char of the 708 * line) adjust the scrolling. 709 */ 710 getvvcol(curwin, &curwin->w_cursor, &s, NULL, &e); 711 if (e > (colnr_T)lastcol) 712 { 713 retval = TRUE; 714 coladvance(s - 1); 715 } 716 else if (s < curwin->w_leftcol) 717 { 718 retval = TRUE; 719 if (coladvance(e + 1) == FAIL) /* there isn't another character */ 720 { 721 curwin->w_leftcol = s; /* adjust w_leftcol instead */ 722 changed_cline_bef_curs(); 723 } 724 } 725 726 if (retval) 727 curwin->w_set_curswant = TRUE; 728 redraw_later(NOT_VALID); 729 return retval; 730 } 731 732 /********************************************************************** 733 * Various routines dealing with allocation and deallocation of memory. 734 */ 735 736 #if defined(MEM_PROFILE) || defined(PROTO) 737 738 # define MEM_SIZES 8200 739 static long_u mem_allocs[MEM_SIZES]; 740 static long_u mem_frees[MEM_SIZES]; 741 static long_u mem_allocated; 742 static long_u mem_freed; 743 static long_u mem_peak; 744 static long_u num_alloc; 745 static long_u num_freed; 746 747 static void mem_pre_alloc_s(size_t *sizep); 748 static void mem_pre_alloc_l(long_u *sizep); 749 static void mem_post_alloc(void **pp, size_t size); 750 static void mem_pre_free(void **pp); 751 752 static void 753 mem_pre_alloc_s(size_t *sizep) 754 { 755 *sizep += sizeof(size_t); 756 } 757 758 static void 759 mem_pre_alloc_l(long_u *sizep) 760 { 761 *sizep += sizeof(size_t); 762 } 763 764 static void 765 mem_post_alloc( 766 void **pp, 767 size_t size) 768 { 769 if (*pp == NULL) 770 return; 771 size -= sizeof(size_t); 772 *(long_u *)*pp = size; 773 if (size <= MEM_SIZES-1) 774 mem_allocs[size-1]++; 775 else 776 mem_allocs[MEM_SIZES-1]++; 777 mem_allocated += size; 778 if (mem_allocated - mem_freed > mem_peak) 779 mem_peak = mem_allocated - mem_freed; 780 num_alloc++; 781 *pp = (void *)((char *)*pp + sizeof(size_t)); 782 } 783 784 static void 785 mem_pre_free(void **pp) 786 { 787 long_u size; 788 789 *pp = (void *)((char *)*pp - sizeof(size_t)); 790 size = *(size_t *)*pp; 791 if (size <= MEM_SIZES-1) 792 mem_frees[size-1]++; 793 else 794 mem_frees[MEM_SIZES-1]++; 795 mem_freed += size; 796 num_freed++; 797 } 798 799 /* 800 * called on exit via atexit() 801 */ 802 void 803 vim_mem_profile_dump(void) 804 { 805 int i, j; 806 807 printf("\r\n"); 808 j = 0; 809 for (i = 0; i < MEM_SIZES - 1; i++) 810 { 811 if (mem_allocs[i] || mem_frees[i]) 812 { 813 if (mem_frees[i] > mem_allocs[i]) 814 printf("\r\n%s", _("ERROR: ")); 815 printf("[%4d / %4lu-%-4lu] ", i + 1, mem_allocs[i], mem_frees[i]); 816 j++; 817 if (j > 3) 818 { 819 j = 0; 820 printf("\r\n"); 821 } 822 } 823 } 824 825 i = MEM_SIZES - 1; 826 if (mem_allocs[i]) 827 { 828 printf("\r\n"); 829 if (mem_frees[i] > mem_allocs[i]) 830 puts(_("ERROR: ")); 831 printf("[>%d / %4lu-%-4lu]", i, mem_allocs[i], mem_frees[i]); 832 } 833 834 printf(_("\n[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"), 835 mem_allocated, mem_freed, mem_allocated - mem_freed, mem_peak); 836 printf(_("[calls] total re/malloc()'s %lu, total free()'s %lu\n\n"), 837 num_alloc, num_freed); 838 } 839 840 #endif /* MEM_PROFILE */ 841 842 #ifdef FEAT_EVAL 843 static int alloc_does_fail(long_u size); 844 845 static int 846 alloc_does_fail(long_u size) 847 { 848 if (alloc_fail_countdown == 0) 849 { 850 if (--alloc_fail_repeat <= 0) 851 alloc_fail_id = 0; 852 do_outofmem_msg(size); 853 return TRUE; 854 } 855 --alloc_fail_countdown; 856 return FALSE; 857 } 858 #endif 859 860 /* 861 * Some memory is reserved for error messages and for being able to 862 * call mf_release_all(), which needs some memory for mf_trans_add(). 863 */ 864 #define KEEP_ROOM (2 * 8192L) 865 #define KEEP_ROOM_KB (KEEP_ROOM / 1024L) 866 867 /* 868 * Note: if unsigned is 16 bits we can only allocate up to 64K with alloc(). 869 * Use lalloc for larger blocks. 870 */ 871 char_u * 872 alloc(unsigned size) 873 { 874 return (lalloc((long_u)size, TRUE)); 875 } 876 877 /* 878 * alloc() with an ID for alloc_fail(). 879 */ 880 char_u * 881 alloc_id(unsigned size, alloc_id_T id UNUSED) 882 { 883 #ifdef FEAT_EVAL 884 if (alloc_fail_id == id && alloc_does_fail((long_u)size)) 885 return NULL; 886 #endif 887 return (lalloc((long_u)size, TRUE)); 888 } 889 890 /* 891 * Allocate memory and set all bytes to zero. 892 */ 893 char_u * 894 alloc_clear(unsigned size) 895 { 896 char_u *p; 897 898 p = lalloc((long_u)size, TRUE); 899 if (p != NULL) 900 (void)vim_memset(p, 0, (size_t)size); 901 return p; 902 } 903 904 /* 905 * alloc() with check for maximum line length 906 */ 907 char_u * 908 alloc_check(unsigned size) 909 { 910 #if !defined(UNIX) 911 if (sizeof(int) == 2 && size > 0x7fff) 912 { 913 /* Don't hide this message */ 914 emsg_silent = 0; 915 EMSG(_("E340: Line is becoming too long")); 916 return NULL; 917 } 918 #endif 919 return (lalloc((long_u)size, TRUE)); 920 } 921 922 /* 923 * Allocate memory like lalloc() and set all bytes to zero. 924 */ 925 char_u * 926 lalloc_clear(long_u size, int message) 927 { 928 char_u *p; 929 930 p = (lalloc(size, message)); 931 if (p != NULL) 932 (void)vim_memset(p, 0, (size_t)size); 933 return p; 934 } 935 936 /* 937 * Low level memory allocation function. 938 * This is used often, KEEP IT FAST! 939 */ 940 char_u * 941 lalloc(long_u size, int message) 942 { 943 char_u *p; /* pointer to new storage space */ 944 static int releasing = FALSE; /* don't do mf_release_all() recursive */ 945 int try_again; 946 #if defined(HAVE_AVAIL_MEM) 947 static long_u allocated = 0; /* allocated since last avail check */ 948 #endif 949 950 /* Safety check for allocating zero bytes */ 951 if (size == 0) 952 { 953 /* Don't hide this message */ 954 emsg_silent = 0; 955 IEMSGN(_("E341: Internal error: lalloc(%ld, )"), size); 956 return NULL; 957 } 958 959 #ifdef MEM_PROFILE 960 mem_pre_alloc_l(&size); 961 #endif 962 963 /* 964 * Loop when out of memory: Try to release some memfile blocks and 965 * if some blocks are released call malloc again. 966 */ 967 for (;;) 968 { 969 /* 970 * Handle three kind of systems: 971 * 1. No check for available memory: Just return. 972 * 2. Slow check for available memory: call mch_avail_mem() after 973 * allocating KEEP_ROOM amount of memory. 974 * 3. Strict check for available memory: call mch_avail_mem() 975 */ 976 if ((p = (char_u *)malloc((size_t)size)) != NULL) 977 { 978 #ifndef HAVE_AVAIL_MEM 979 /* 1. No check for available memory: Just return. */ 980 goto theend; 981 #else 982 /* 2. Slow check for available memory: call mch_avail_mem() after 983 * allocating (KEEP_ROOM / 2) amount of memory. */ 984 allocated += size; 985 if (allocated < KEEP_ROOM / 2) 986 goto theend; 987 allocated = 0; 988 989 /* 3. check for available memory: call mch_avail_mem() */ 990 if (mch_avail_mem(TRUE) < KEEP_ROOM_KB && !releasing) 991 { 992 free((char *)p); /* System is low... no go! */ 993 p = NULL; 994 } 995 else 996 goto theend; 997 #endif 998 } 999 /* 1000 * Remember that mf_release_all() is being called to avoid an endless 1001 * loop, because mf_release_all() may call alloc() recursively. 1002 */ 1003 if (releasing) 1004 break; 1005 releasing = TRUE; 1006 1007 clear_sb_text(TRUE); /* free any scrollback text */ 1008 try_again = mf_release_all(); /* release as many blocks as possible */ 1009 1010 releasing = FALSE; 1011 if (!try_again) 1012 break; 1013 } 1014 1015 if (message && p == NULL) 1016 do_outofmem_msg(size); 1017 1018 theend: 1019 #ifdef MEM_PROFILE 1020 mem_post_alloc((void **)&p, (size_t)size); 1021 #endif 1022 return p; 1023 } 1024 1025 /* 1026 * lalloc() with an ID for alloc_fail(). 1027 */ 1028 char_u * 1029 lalloc_id(long_u size, int message, alloc_id_T id UNUSED) 1030 { 1031 #ifdef FEAT_EVAL 1032 if (alloc_fail_id == id && alloc_does_fail(size)) 1033 return NULL; 1034 #endif 1035 return (lalloc((long_u)size, message)); 1036 } 1037 1038 #if defined(MEM_PROFILE) || defined(PROTO) 1039 /* 1040 * realloc() with memory profiling. 1041 */ 1042 void * 1043 mem_realloc(void *ptr, size_t size) 1044 { 1045 void *p; 1046 1047 mem_pre_free(&ptr); 1048 mem_pre_alloc_s(&size); 1049 1050 p = realloc(ptr, size); 1051 1052 mem_post_alloc(&p, size); 1053 1054 return p; 1055 } 1056 #endif 1057 1058 /* 1059 * Avoid repeating the error message many times (they take 1 second each). 1060 * Did_outofmem_msg is reset when a character is read. 1061 */ 1062 void 1063 do_outofmem_msg(long_u size) 1064 { 1065 if (!did_outofmem_msg) 1066 { 1067 /* Don't hide this message */ 1068 emsg_silent = 0; 1069 1070 /* Must come first to avoid coming back here when printing the error 1071 * message fails, e.g. when setting v:errmsg. */ 1072 did_outofmem_msg = TRUE; 1073 1074 EMSGN(_("E342: Out of memory! (allocating %lu bytes)"), size); 1075 } 1076 } 1077 1078 #if defined(EXITFREE) || defined(PROTO) 1079 1080 # if defined(FEAT_SEARCHPATH) 1081 static void free_findfile(void); 1082 # endif 1083 1084 /* 1085 * Free everything that we allocated. 1086 * Can be used to detect memory leaks, e.g., with ccmalloc. 1087 * NOTE: This is tricky! Things are freed that functions depend on. Don't be 1088 * surprised if Vim crashes... 1089 * Some things can't be freed, esp. things local to a library function. 1090 */ 1091 void 1092 free_all_mem(void) 1093 { 1094 buf_T *buf, *nextbuf; 1095 1096 /* When we cause a crash here it is caught and Vim tries to exit cleanly. 1097 * Don't try freeing everything again. */ 1098 if (entered_free_all_mem) 1099 return; 1100 entered_free_all_mem = TRUE; 1101 1102 # ifdef FEAT_AUTOCMD 1103 /* Don't want to trigger autocommands from here on. */ 1104 block_autocmds(); 1105 # endif 1106 1107 /* Close all tabs and windows. Reset 'equalalways' to avoid redraws. */ 1108 p_ea = FALSE; 1109 if (first_tabpage->tp_next != NULL) 1110 do_cmdline_cmd((char_u *)"tabonly!"); 1111 if (!ONE_WINDOW) 1112 do_cmdline_cmd((char_u *)"only!"); 1113 1114 # if defined(FEAT_SPELL) 1115 /* Free all spell info. */ 1116 spell_free_all(); 1117 # endif 1118 1119 #if defined(FEAT_INS_EXPAND) && defined(FEAT_BEVAL_TERM) 1120 ui_remove_balloon(); 1121 # endif 1122 1123 # if defined(FEAT_USR_CMDS) 1124 /* Clear user commands (before deleting buffers). */ 1125 ex_comclear(NULL); 1126 # endif 1127 1128 # ifdef FEAT_MENU 1129 /* Clear menus. */ 1130 do_cmdline_cmd((char_u *)"aunmenu *"); 1131 # ifdef FEAT_MULTI_LANG 1132 do_cmdline_cmd((char_u *)"menutranslate clear"); 1133 # endif 1134 # endif 1135 1136 /* Clear mappings, abbreviations, breakpoints. */ 1137 do_cmdline_cmd((char_u *)"lmapclear"); 1138 do_cmdline_cmd((char_u *)"xmapclear"); 1139 do_cmdline_cmd((char_u *)"mapclear"); 1140 do_cmdline_cmd((char_u *)"mapclear!"); 1141 do_cmdline_cmd((char_u *)"abclear"); 1142 # if defined(FEAT_EVAL) 1143 do_cmdline_cmd((char_u *)"breakdel *"); 1144 # endif 1145 # if defined(FEAT_PROFILE) 1146 do_cmdline_cmd((char_u *)"profdel *"); 1147 # endif 1148 # if defined(FEAT_KEYMAP) 1149 do_cmdline_cmd((char_u *)"set keymap="); 1150 #endif 1151 1152 # ifdef FEAT_TITLE 1153 free_titles(); 1154 # endif 1155 # if defined(FEAT_SEARCHPATH) 1156 free_findfile(); 1157 # endif 1158 1159 /* Obviously named calls. */ 1160 # if defined(FEAT_AUTOCMD) 1161 free_all_autocmds(); 1162 # endif 1163 clear_termcodes(); 1164 free_all_marks(); 1165 alist_clear(&global_alist); 1166 free_homedir(); 1167 # if defined(FEAT_CMDL_COMPL) 1168 free_users(); 1169 # endif 1170 free_search_patterns(); 1171 free_old_sub(); 1172 free_last_insert(); 1173 free_prev_shellcmd(); 1174 free_regexp_stuff(); 1175 free_tag_stuff(); 1176 free_cd_dir(); 1177 # ifdef FEAT_SIGNS 1178 free_signs(); 1179 # endif 1180 # ifdef FEAT_EVAL 1181 set_expr_line(NULL); 1182 # endif 1183 # ifdef FEAT_DIFF 1184 diff_clear(curtab); 1185 # endif 1186 clear_sb_text(TRUE); /* free any scrollback text */ 1187 1188 /* Free some global vars. */ 1189 vim_free(username); 1190 # ifdef FEAT_CLIPBOARD 1191 vim_regfree(clip_exclude_prog); 1192 # endif 1193 vim_free(last_cmdline); 1194 # ifdef FEAT_CMDHIST 1195 vim_free(new_last_cmdline); 1196 # endif 1197 set_keep_msg(NULL, 0); 1198 vim_free(ff_expand_buffer); 1199 1200 /* Clear cmdline history. */ 1201 p_hi = 0; 1202 # ifdef FEAT_CMDHIST 1203 init_history(); 1204 # endif 1205 1206 #ifdef FEAT_QUICKFIX 1207 { 1208 win_T *win; 1209 tabpage_T *tab; 1210 1211 qf_free_all(NULL); 1212 /* Free all location lists */ 1213 FOR_ALL_TAB_WINDOWS(tab, win) 1214 qf_free_all(win); 1215 } 1216 #endif 1217 1218 /* Close all script inputs. */ 1219 close_all_scripts(); 1220 1221 /* Destroy all windows. Must come before freeing buffers. */ 1222 win_free_all(); 1223 1224 /* Free all option values. Must come after closing windows. */ 1225 free_all_options(); 1226 1227 /* Free all buffers. Reset 'autochdir' to avoid accessing things that 1228 * were freed already. */ 1229 #ifdef FEAT_AUTOCHDIR 1230 p_acd = FALSE; 1231 #endif 1232 for (buf = firstbuf; buf != NULL; ) 1233 { 1234 bufref_T bufref; 1235 1236 set_bufref(&bufref, buf); 1237 nextbuf = buf->b_next; 1238 close_buffer(NULL, buf, DOBUF_WIPE, FALSE); 1239 if (bufref_valid(&bufref)) 1240 buf = nextbuf; /* didn't work, try next one */ 1241 else 1242 buf = firstbuf; 1243 } 1244 1245 #ifdef FEAT_ARABIC 1246 free_cmdline_buf(); 1247 #endif 1248 1249 /* Clear registers. */ 1250 clear_registers(); 1251 ResetRedobuff(); 1252 ResetRedobuff(); 1253 1254 #if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) 1255 vim_free(serverDelayedStartName); 1256 #endif 1257 1258 /* highlight info */ 1259 free_highlight(); 1260 1261 reset_last_sourcing(); 1262 1263 free_tabpage(first_tabpage); 1264 first_tabpage = NULL; 1265 1266 # ifdef UNIX 1267 /* Machine-specific free. */ 1268 mch_free_mem(); 1269 # endif 1270 1271 /* message history */ 1272 for (;;) 1273 if (delete_first_msg() == FAIL) 1274 break; 1275 1276 # ifdef FEAT_JOB_CHANNEL 1277 channel_free_all(); 1278 # endif 1279 #ifdef FEAT_TIMERS 1280 timer_free_all(); 1281 #endif 1282 # ifdef FEAT_EVAL 1283 /* must be after channel_free_all() with unrefs partials */ 1284 eval_clear(); 1285 # endif 1286 # ifdef FEAT_JOB_CHANNEL 1287 /* must be after eval_clear() with unrefs jobs */ 1288 job_free_all(); 1289 # endif 1290 1291 free_termoptions(); 1292 1293 /* screenlines (can't display anything now!) */ 1294 free_screenlines(); 1295 1296 #if defined(USE_XSMP) 1297 xsmp_close(); 1298 #endif 1299 #ifdef FEAT_GUI_GTK 1300 gui_mch_free_all(); 1301 #endif 1302 clear_hl_tables(); 1303 1304 vim_free(IObuff); 1305 vim_free(NameBuff); 1306 } 1307 #endif 1308 1309 /* 1310 * Copy "string" into newly allocated memory. 1311 */ 1312 char_u * 1313 vim_strsave(char_u *string) 1314 { 1315 char_u *p; 1316 unsigned len; 1317 1318 len = (unsigned)STRLEN(string) + 1; 1319 p = alloc(len); 1320 if (p != NULL) 1321 mch_memmove(p, string, (size_t)len); 1322 return p; 1323 } 1324 1325 /* 1326 * Copy up to "len" bytes of "string" into newly allocated memory and 1327 * terminate with a NUL. 1328 * The allocated memory always has size "len + 1", also when "string" is 1329 * shorter. 1330 */ 1331 char_u * 1332 vim_strnsave(char_u *string, int len) 1333 { 1334 char_u *p; 1335 1336 p = alloc((unsigned)(len + 1)); 1337 if (p != NULL) 1338 { 1339 STRNCPY(p, string, len); 1340 p[len] = NUL; 1341 } 1342 return p; 1343 } 1344 1345 /* 1346 * Same as vim_strsave(), but any characters found in esc_chars are preceded 1347 * by a backslash. 1348 */ 1349 char_u * 1350 vim_strsave_escaped(char_u *string, char_u *esc_chars) 1351 { 1352 return vim_strsave_escaped_ext(string, esc_chars, '\\', FALSE); 1353 } 1354 1355 /* 1356 * Same as vim_strsave_escaped(), but when "bsl" is TRUE also escape 1357 * characters where rem_backslash() would remove the backslash. 1358 * Escape the characters with "cc". 1359 */ 1360 char_u * 1361 vim_strsave_escaped_ext( 1362 char_u *string, 1363 char_u *esc_chars, 1364 int cc, 1365 int bsl) 1366 { 1367 char_u *p; 1368 char_u *p2; 1369 char_u *escaped_string; 1370 unsigned length; 1371 #ifdef FEAT_MBYTE 1372 int l; 1373 #endif 1374 1375 /* 1376 * First count the number of backslashes required. 1377 * Then allocate the memory and insert them. 1378 */ 1379 length = 1; /* count the trailing NUL */ 1380 for (p = string; *p; p++) 1381 { 1382 #ifdef FEAT_MBYTE 1383 if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) 1384 { 1385 length += l; /* count a multibyte char */ 1386 p += l - 1; 1387 continue; 1388 } 1389 #endif 1390 if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p))) 1391 ++length; /* count a backslash */ 1392 ++length; /* count an ordinary char */ 1393 } 1394 escaped_string = alloc(length); 1395 if (escaped_string != NULL) 1396 { 1397 p2 = escaped_string; 1398 for (p = string; *p; p++) 1399 { 1400 #ifdef FEAT_MBYTE 1401 if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) 1402 { 1403 mch_memmove(p2, p, (size_t)l); 1404 p2 += l; 1405 p += l - 1; /* skip multibyte char */ 1406 continue; 1407 } 1408 #endif 1409 if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p))) 1410 *p2++ = cc; 1411 *p2++ = *p; 1412 } 1413 *p2 = NUL; 1414 } 1415 return escaped_string; 1416 } 1417 1418 /* 1419 * Return TRUE when 'shell' has "csh" in the tail. 1420 */ 1421 int 1422 csh_like_shell(void) 1423 { 1424 return (strstr((char *)gettail(p_sh), "csh") != NULL); 1425 } 1426 1427 /* 1428 * Escape "string" for use as a shell argument with system(). 1429 * This uses single quotes, except when we know we need to use double quotes 1430 * (MS-DOS and MS-Windows without 'shellslash' set). 1431 * Escape a newline, depending on the 'shell' option. 1432 * When "do_special" is TRUE also replace "!", "%", "#" and things starting 1433 * with "<" like "<cfile>". 1434 * When "do_newline" is FALSE do not escape newline unless it is csh shell. 1435 * Returns the result in allocated memory, NULL if we have run out. 1436 */ 1437 char_u * 1438 vim_strsave_shellescape(char_u *string, int do_special, int do_newline) 1439 { 1440 unsigned length; 1441 char_u *p; 1442 char_u *d; 1443 char_u *escaped_string; 1444 int l; 1445 int csh_like; 1446 1447 /* Only csh and similar shells expand '!' within single quotes. For sh and 1448 * the like we must not put a backslash before it, it will be taken 1449 * literally. If do_special is set the '!' will be escaped twice. 1450 * Csh also needs to have "\n" escaped twice when do_special is set. */ 1451 csh_like = csh_like_shell(); 1452 1453 /* First count the number of extra bytes required. */ 1454 length = (unsigned)STRLEN(string) + 3; /* two quotes and a trailing NUL */ 1455 for (p = string; *p != NUL; MB_PTR_ADV(p)) 1456 { 1457 # ifdef WIN32 1458 if (!p_ssl) 1459 { 1460 if (*p == '"') 1461 ++length; /* " -> "" */ 1462 } 1463 else 1464 # endif 1465 if (*p == '\'') 1466 length += 3; /* ' => '\'' */ 1467 if ((*p == '\n' && (csh_like || do_newline)) 1468 || (*p == '!' && (csh_like || do_special))) 1469 { 1470 ++length; /* insert backslash */ 1471 if (csh_like && do_special) 1472 ++length; /* insert backslash */ 1473 } 1474 if (do_special && find_cmdline_var(p, &l) >= 0) 1475 { 1476 ++length; /* insert backslash */ 1477 p += l - 1; 1478 } 1479 } 1480 1481 /* Allocate memory for the result and fill it. */ 1482 escaped_string = alloc(length); 1483 if (escaped_string != NULL) 1484 { 1485 d = escaped_string; 1486 1487 /* add opening quote */ 1488 # ifdef WIN32 1489 if (!p_ssl) 1490 *d++ = '"'; 1491 else 1492 # endif 1493 *d++ = '\''; 1494 1495 for (p = string; *p != NUL; ) 1496 { 1497 # ifdef WIN32 1498 if (!p_ssl) 1499 { 1500 if (*p == '"') 1501 { 1502 *d++ = '"'; 1503 *d++ = '"'; 1504 ++p; 1505 continue; 1506 } 1507 } 1508 else 1509 # endif 1510 if (*p == '\'') 1511 { 1512 *d++ = '\''; 1513 *d++ = '\\'; 1514 *d++ = '\''; 1515 *d++ = '\''; 1516 ++p; 1517 continue; 1518 } 1519 if ((*p == '\n' && (csh_like || do_newline)) 1520 || (*p == '!' && (csh_like || do_special))) 1521 { 1522 *d++ = '\\'; 1523 if (csh_like && do_special) 1524 *d++ = '\\'; 1525 *d++ = *p++; 1526 continue; 1527 } 1528 if (do_special && find_cmdline_var(p, &l) >= 0) 1529 { 1530 *d++ = '\\'; /* insert backslash */ 1531 while (--l >= 0) /* copy the var */ 1532 *d++ = *p++; 1533 continue; 1534 } 1535 1536 MB_COPY_CHAR(p, d); 1537 } 1538 1539 /* add terminating quote and finish with a NUL */ 1540 # ifdef WIN32 1541 if (!p_ssl) 1542 *d++ = '"'; 1543 else 1544 # endif 1545 *d++ = '\''; 1546 *d = NUL; 1547 } 1548 1549 return escaped_string; 1550 } 1551 1552 /* 1553 * Like vim_strsave(), but make all characters uppercase. 1554 * This uses ASCII lower-to-upper case translation, language independent. 1555 */ 1556 char_u * 1557 vim_strsave_up(char_u *string) 1558 { 1559 char_u *p1; 1560 1561 p1 = vim_strsave(string); 1562 vim_strup(p1); 1563 return p1; 1564 } 1565 1566 /* 1567 * Like vim_strnsave(), but make all characters uppercase. 1568 * This uses ASCII lower-to-upper case translation, language independent. 1569 */ 1570 char_u * 1571 vim_strnsave_up(char_u *string, int len) 1572 { 1573 char_u *p1; 1574 1575 p1 = vim_strnsave(string, len); 1576 vim_strup(p1); 1577 return p1; 1578 } 1579 1580 /* 1581 * ASCII lower-to-upper case translation, language independent. 1582 */ 1583 void 1584 vim_strup( 1585 char_u *p) 1586 { 1587 char_u *p2; 1588 int c; 1589 1590 if (p != NULL) 1591 { 1592 p2 = p; 1593 while ((c = *p2) != NUL) 1594 #ifdef EBCDIC 1595 *p2++ = isalpha(c) ? toupper(c) : c; 1596 #else 1597 *p2++ = (c < 'a' || c > 'z') ? c : (c - 0x20); 1598 #endif 1599 } 1600 } 1601 1602 #if defined(FEAT_EVAL) || defined(FEAT_SPELL) || defined(PROTO) 1603 /* 1604 * Make string "s" all upper-case and return it in allocated memory. 1605 * Handles multi-byte characters as well as possible. 1606 * Returns NULL when out of memory. 1607 */ 1608 char_u * 1609 strup_save(char_u *orig) 1610 { 1611 char_u *p; 1612 char_u *res; 1613 1614 res = p = vim_strsave(orig); 1615 1616 if (res != NULL) 1617 while (*p != NUL) 1618 { 1619 # ifdef FEAT_MBYTE 1620 int l; 1621 1622 if (enc_utf8) 1623 { 1624 int c, uc; 1625 int newl; 1626 char_u *s; 1627 1628 c = utf_ptr2char(p); 1629 l = utf_ptr2len(p); 1630 if (c == 0) 1631 { 1632 /* overlong sequence, use only the first byte */ 1633 c = *p; 1634 l = 1; 1635 } 1636 uc = utf_toupper(c); 1637 1638 /* Reallocate string when byte count changes. This is rare, 1639 * thus it's OK to do another malloc()/free(). */ 1640 newl = utf_char2len(uc); 1641 if (newl != l) 1642 { 1643 s = alloc((unsigned)STRLEN(res) + 1 + newl - l); 1644 if (s == NULL) 1645 { 1646 vim_free(res); 1647 return NULL; 1648 } 1649 mch_memmove(s, res, p - res); 1650 STRCPY(s + (p - res) + newl, p + l); 1651 p = s + (p - res); 1652 vim_free(res); 1653 res = s; 1654 } 1655 1656 utf_char2bytes(uc, p); 1657 p += newl; 1658 } 1659 else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) 1660 p += l; /* skip multi-byte character */ 1661 else 1662 # endif 1663 { 1664 *p = TOUPPER_LOC(*p); /* note that toupper() can be a macro */ 1665 p++; 1666 } 1667 } 1668 1669 return res; 1670 } 1671 1672 /* 1673 * Make string "s" all lower-case and return it in allocated memory. 1674 * Handles multi-byte characters as well as possible. 1675 * Returns NULL when out of memory. 1676 */ 1677 char_u * 1678 strlow_save(char_u *orig) 1679 { 1680 char_u *p; 1681 char_u *res; 1682 1683 res = p = vim_strsave(orig); 1684 1685 if (res != NULL) 1686 while (*p != NUL) 1687 { 1688 # ifdef FEAT_MBYTE 1689 int l; 1690 1691 if (enc_utf8) 1692 { 1693 int c, lc; 1694 int newl; 1695 char_u *s; 1696 1697 c = utf_ptr2char(p); 1698 l = utf_ptr2len(p); 1699 if (c == 0) 1700 { 1701 /* overlong sequence, use only the first byte */ 1702 c = *p; 1703 l = 1; 1704 } 1705 lc = utf_tolower(c); 1706 1707 /* Reallocate string when byte count changes. This is rare, 1708 * thus it's OK to do another malloc()/free(). */ 1709 newl = utf_char2len(lc); 1710 if (newl != l) 1711 { 1712 s = alloc((unsigned)STRLEN(res) + 1 + newl - l); 1713 if (s == NULL) 1714 { 1715 vim_free(res); 1716 return NULL; 1717 } 1718 mch_memmove(s, res, p - res); 1719 STRCPY(s + (p - res) + newl, p + l); 1720 p = s + (p - res); 1721 vim_free(res); 1722 res = s; 1723 } 1724 1725 utf_char2bytes(lc, p); 1726 p += newl; 1727 } 1728 else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) 1729 p += l; /* skip multi-byte character */ 1730 else 1731 # endif 1732 { 1733 *p = TOLOWER_LOC(*p); /* note that tolower() can be a macro */ 1734 p++; 1735 } 1736 } 1737 1738 return res; 1739 } 1740 #endif 1741 1742 /* 1743 * delete spaces at the end of a string 1744 */ 1745 void 1746 del_trailing_spaces(char_u *ptr) 1747 { 1748 char_u *q; 1749 1750 q = ptr + STRLEN(ptr); 1751 while (--q > ptr && VIM_ISWHITE(q[0]) && q[-1] != '\\' && q[-1] != Ctrl_V) 1752 *q = NUL; 1753 } 1754 1755 /* 1756 * Like strncpy(), but always terminate the result with one NUL. 1757 * "to" must be "len + 1" long! 1758 */ 1759 void 1760 vim_strncpy(char_u *to, char_u *from, size_t len) 1761 { 1762 STRNCPY(to, from, len); 1763 to[len] = NUL; 1764 } 1765 1766 /* 1767 * Like strcat(), but make sure the result fits in "tosize" bytes and is 1768 * always NUL terminated. "from" and "to" may overlap. 1769 */ 1770 void 1771 vim_strcat(char_u *to, char_u *from, size_t tosize) 1772 { 1773 size_t tolen = STRLEN(to); 1774 size_t fromlen = STRLEN(from); 1775 1776 if (tolen + fromlen + 1 > tosize) 1777 { 1778 mch_memmove(to + tolen, from, tosize - tolen - 1); 1779 to[tosize - 1] = NUL; 1780 } 1781 else 1782 mch_memmove(to + tolen, from, fromlen + 1); 1783 } 1784 1785 /* 1786 * Isolate one part of a string option where parts are separated with 1787 * "sep_chars". 1788 * The part is copied into "buf[maxlen]". 1789 * "*option" is advanced to the next part. 1790 * The length is returned. 1791 */ 1792 int 1793 copy_option_part( 1794 char_u **option, 1795 char_u *buf, 1796 int maxlen, 1797 char *sep_chars) 1798 { 1799 int len = 0; 1800 char_u *p = *option; 1801 1802 /* skip '.' at start of option part, for 'suffixes' */ 1803 if (*p == '.') 1804 buf[len++] = *p++; 1805 while (*p != NUL && vim_strchr((char_u *)sep_chars, *p) == NULL) 1806 { 1807 /* 1808 * Skip backslash before a separator character and space. 1809 */ 1810 if (p[0] == '\\' && vim_strchr((char_u *)sep_chars, p[1]) != NULL) 1811 ++p; 1812 if (len < maxlen - 1) 1813 buf[len++] = *p; 1814 ++p; 1815 } 1816 buf[len] = NUL; 1817 1818 if (*p != NUL && *p != ',') /* skip non-standard separator */ 1819 ++p; 1820 p = skip_to_option_part(p); /* p points to next file name */ 1821 1822 *option = p; 1823 return len; 1824 } 1825 1826 /* 1827 * Replacement for free() that ignores NULL pointers. 1828 * Also skip free() when exiting for sure, this helps when we caught a deadly 1829 * signal that was caused by a crash in free(). 1830 * If you want to set NULL after calling this function, you should use 1831 * VIM_CLEAR() instead. 1832 */ 1833 void 1834 vim_free(void *x) 1835 { 1836 if (x != NULL && !really_exiting) 1837 { 1838 #ifdef MEM_PROFILE 1839 mem_pre_free(&x); 1840 #endif 1841 free(x); 1842 } 1843 } 1844 1845 #ifndef HAVE_MEMSET 1846 void * 1847 vim_memset(void *ptr, int c, size_t size) 1848 { 1849 char *p = ptr; 1850 1851 while (size-- > 0) 1852 *p++ = c; 1853 return ptr; 1854 } 1855 #endif 1856 1857 #if (!defined(HAVE_STRCASECMP) && !defined(HAVE_STRICMP)) || defined(PROTO) 1858 /* 1859 * Compare two strings, ignoring case, using current locale. 1860 * Doesn't work for multi-byte characters. 1861 * return 0 for match, < 0 for smaller, > 0 for bigger 1862 */ 1863 int 1864 vim_stricmp(char *s1, char *s2) 1865 { 1866 int i; 1867 1868 for (;;) 1869 { 1870 i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2); 1871 if (i != 0) 1872 return i; /* this character different */ 1873 if (*s1 == NUL) 1874 break; /* strings match until NUL */ 1875 ++s1; 1876 ++s2; 1877 } 1878 return 0; /* strings match */ 1879 } 1880 #endif 1881 1882 #if (!defined(HAVE_STRNCASECMP) && !defined(HAVE_STRNICMP)) || defined(PROTO) 1883 /* 1884 * Compare two strings, for length "len", ignoring case, using current locale. 1885 * Doesn't work for multi-byte characters. 1886 * return 0 for match, < 0 for smaller, > 0 for bigger 1887 */ 1888 int 1889 vim_strnicmp(char *s1, char *s2, size_t len) 1890 { 1891 int i; 1892 1893 while (len > 0) 1894 { 1895 i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2); 1896 if (i != 0) 1897 return i; /* this character different */ 1898 if (*s1 == NUL) 1899 break; /* strings match until NUL */ 1900 ++s1; 1901 ++s2; 1902 --len; 1903 } 1904 return 0; /* strings match */ 1905 } 1906 #endif 1907 1908 /* 1909 * Version of strchr() and strrchr() that handle unsigned char strings 1910 * with characters from 128 to 255 correctly. It also doesn't return a 1911 * pointer to the NUL at the end of the string. 1912 */ 1913 char_u * 1914 vim_strchr(char_u *string, int c) 1915 { 1916 char_u *p; 1917 int b; 1918 1919 p = string; 1920 #ifdef FEAT_MBYTE 1921 if (enc_utf8 && c >= 0x80) 1922 { 1923 while (*p != NUL) 1924 { 1925 int l = utfc_ptr2len(p); 1926 1927 /* Avoid matching an illegal byte here. */ 1928 if (utf_ptr2char(p) == c && l > 1) 1929 return p; 1930 p += l; 1931 } 1932 return NULL; 1933 } 1934 if (enc_dbcs != 0 && c > 255) 1935 { 1936 int n2 = c & 0xff; 1937 1938 c = ((unsigned)c >> 8) & 0xff; 1939 while ((b = *p) != NUL) 1940 { 1941 if (b == c && p[1] == n2) 1942 return p; 1943 p += (*mb_ptr2len)(p); 1944 } 1945 return NULL; 1946 } 1947 if (has_mbyte) 1948 { 1949 while ((b = *p) != NUL) 1950 { 1951 if (b == c) 1952 return p; 1953 p += (*mb_ptr2len)(p); 1954 } 1955 return NULL; 1956 } 1957 #endif 1958 while ((b = *p) != NUL) 1959 { 1960 if (b == c) 1961 return p; 1962 ++p; 1963 } 1964 return NULL; 1965 } 1966 1967 /* 1968 * Version of strchr() that only works for bytes and handles unsigned char 1969 * strings with characters above 128 correctly. It also doesn't return a 1970 * pointer to the NUL at the end of the string. 1971 */ 1972 char_u * 1973 vim_strbyte(char_u *string, int c) 1974 { 1975 char_u *p = string; 1976 1977 while (*p != NUL) 1978 { 1979 if (*p == c) 1980 return p; 1981 ++p; 1982 } 1983 return NULL; 1984 } 1985 1986 /* 1987 * Search for last occurrence of "c" in "string". 1988 * Return NULL if not found. 1989 * Does not handle multi-byte char for "c"! 1990 */ 1991 char_u * 1992 vim_strrchr(char_u *string, int c) 1993 { 1994 char_u *retval = NULL; 1995 char_u *p = string; 1996 1997 while (*p) 1998 { 1999 if (*p == c) 2000 retval = p; 2001 MB_PTR_ADV(p); 2002 } 2003 return retval; 2004 } 2005 2006 /* 2007 * Vim's version of strpbrk(), in case it's missing. 2008 * Don't generate a prototype for this, causes problems when it's not used. 2009 */ 2010 #ifndef PROTO 2011 # ifndef HAVE_STRPBRK 2012 # ifdef vim_strpbrk 2013 # undef vim_strpbrk 2014 # endif 2015 char_u * 2016 vim_strpbrk(char_u *s, char_u *charset) 2017 { 2018 while (*s) 2019 { 2020 if (vim_strchr(charset, *s) != NULL) 2021 return s; 2022 MB_PTR_ADV(s); 2023 } 2024 return NULL; 2025 } 2026 # endif 2027 #endif 2028 2029 /* 2030 * Vim has its own isspace() function, because on some machines isspace() 2031 * can't handle characters above 128. 2032 */ 2033 int 2034 vim_isspace(int x) 2035 { 2036 return ((x >= 9 && x <= 13) || x == ' '); 2037 } 2038 2039 /************************************************************************ 2040 * Functions for handling growing arrays. 2041 */ 2042 2043 /* 2044 * Clear an allocated growing array. 2045 */ 2046 void 2047 ga_clear(garray_T *gap) 2048 { 2049 vim_free(gap->ga_data); 2050 ga_init(gap); 2051 } 2052 2053 /* 2054 * Clear a growing array that contains a list of strings. 2055 */ 2056 void 2057 ga_clear_strings(garray_T *gap) 2058 { 2059 int i; 2060 2061 for (i = 0; i < gap->ga_len; ++i) 2062 vim_free(((char_u **)(gap->ga_data))[i]); 2063 ga_clear(gap); 2064 } 2065 2066 /* 2067 * Initialize a growing array. Don't forget to set ga_itemsize and 2068 * ga_growsize! Or use ga_init2(). 2069 */ 2070 void 2071 ga_init(garray_T *gap) 2072 { 2073 gap->ga_data = NULL; 2074 gap->ga_maxlen = 0; 2075 gap->ga_len = 0; 2076 } 2077 2078 void 2079 ga_init2(garray_T *gap, int itemsize, int growsize) 2080 { 2081 ga_init(gap); 2082 gap->ga_itemsize = itemsize; 2083 gap->ga_growsize = growsize; 2084 } 2085 2086 /* 2087 * Make room in growing array "gap" for at least "n" items. 2088 * Return FAIL for failure, OK otherwise. 2089 */ 2090 int 2091 ga_grow(garray_T *gap, int n) 2092 { 2093 size_t old_len; 2094 size_t new_len; 2095 char_u *pp; 2096 2097 if (gap->ga_maxlen - gap->ga_len < n) 2098 { 2099 if (n < gap->ga_growsize) 2100 n = gap->ga_growsize; 2101 new_len = gap->ga_itemsize * (gap->ga_len + n); 2102 pp = (gap->ga_data == NULL) 2103 ? alloc((unsigned)new_len) : vim_realloc(gap->ga_data, new_len); 2104 if (pp == NULL) 2105 return FAIL; 2106 old_len = gap->ga_itemsize * gap->ga_maxlen; 2107 vim_memset(pp + old_len, 0, new_len - old_len); 2108 gap->ga_maxlen = gap->ga_len + n; 2109 gap->ga_data = pp; 2110 } 2111 return OK; 2112 } 2113 2114 /* 2115 * For a growing array that contains a list of strings: concatenate all the 2116 * strings with a separating "sep". 2117 * Returns NULL when out of memory. 2118 */ 2119 char_u * 2120 ga_concat_strings(garray_T *gap, char *sep) 2121 { 2122 int i; 2123 int len = 0; 2124 int sep_len = (int)STRLEN(sep); 2125 char_u *s; 2126 char_u *p; 2127 2128 for (i = 0; i < gap->ga_len; ++i) 2129 len += (int)STRLEN(((char_u **)(gap->ga_data))[i]) + sep_len; 2130 2131 s = alloc(len + 1); 2132 if (s != NULL) 2133 { 2134 *s = NUL; 2135 p = s; 2136 for (i = 0; i < gap->ga_len; ++i) 2137 { 2138 if (p != s) 2139 { 2140 STRCPY(p, sep); 2141 p += sep_len; 2142 } 2143 STRCPY(p, ((char_u **)(gap->ga_data))[i]); 2144 p += STRLEN(p); 2145 } 2146 } 2147 return s; 2148 } 2149 2150 #if defined(FEAT_VIMINFO) || defined(FEAT_EVAL) || defined(PROTO) 2151 /* 2152 * Make a copy of string "p" and add it to "gap". 2153 * When out of memory nothing changes. 2154 */ 2155 void 2156 ga_add_string(garray_T *gap, char_u *p) 2157 { 2158 char_u *cp = vim_strsave(p); 2159 2160 if (cp != NULL) 2161 { 2162 if (ga_grow(gap, 1) == OK) 2163 ((char_u **)(gap->ga_data))[gap->ga_len++] = cp; 2164 else 2165 vim_free(cp); 2166 } 2167 } 2168 #endif 2169 2170 /* 2171 * Concatenate a string to a growarray which contains characters. 2172 * When "s" is NULL does not do anything. 2173 * Note: Does NOT copy the NUL at the end! 2174 */ 2175 void 2176 ga_concat(garray_T *gap, char_u *s) 2177 { 2178 int len; 2179 2180 if (s == NULL || *s == NUL) 2181 return; 2182 len = (int)STRLEN(s); 2183 if (ga_grow(gap, len) == OK) 2184 { 2185 mch_memmove((char *)gap->ga_data + gap->ga_len, s, (size_t)len); 2186 gap->ga_len += len; 2187 } 2188 } 2189 2190 /* 2191 * Append one byte to a growarray which contains bytes. 2192 */ 2193 void 2194 ga_append(garray_T *gap, int c) 2195 { 2196 if (ga_grow(gap, 1) == OK) 2197 { 2198 *((char *)gap->ga_data + gap->ga_len) = c; 2199 ++gap->ga_len; 2200 } 2201 } 2202 2203 #if (defined(UNIX) && !defined(USE_SYSTEM)) || defined(WIN3264) \ 2204 || defined(PROTO) 2205 /* 2206 * Append the text in "gap" below the cursor line and clear "gap". 2207 */ 2208 void 2209 append_ga_line(garray_T *gap) 2210 { 2211 /* Remove trailing CR. */ 2212 if (gap->ga_len > 0 2213 && !curbuf->b_p_bin 2214 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR) 2215 --gap->ga_len; 2216 ga_append(gap, NUL); 2217 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE); 2218 gap->ga_len = 0; 2219 } 2220 #endif 2221 2222 /************************************************************************ 2223 * functions that use lookup tables for various things, generally to do with 2224 * special key codes. 2225 */ 2226 2227 /* 2228 * Some useful tables. 2229 */ 2230 2231 static struct modmasktable 2232 { 2233 short mod_mask; /* Bit-mask for particular key modifier */ 2234 short mod_flag; /* Bit(s) for particular key modifier */ 2235 char_u name; /* Single letter name of modifier */ 2236 } mod_mask_table[] = 2237 { 2238 {MOD_MASK_ALT, MOD_MASK_ALT, (char_u)'M'}, 2239 {MOD_MASK_META, MOD_MASK_META, (char_u)'T'}, 2240 {MOD_MASK_CTRL, MOD_MASK_CTRL, (char_u)'C'}, 2241 {MOD_MASK_SHIFT, MOD_MASK_SHIFT, (char_u)'S'}, 2242 {MOD_MASK_MULTI_CLICK, MOD_MASK_2CLICK, (char_u)'2'}, 2243 {MOD_MASK_MULTI_CLICK, MOD_MASK_3CLICK, (char_u)'3'}, 2244 {MOD_MASK_MULTI_CLICK, MOD_MASK_4CLICK, (char_u)'4'}, 2245 #ifdef MACOS_X 2246 {MOD_MASK_CMD, MOD_MASK_CMD, (char_u)'D'}, 2247 #endif 2248 /* 'A' must be the last one */ 2249 {MOD_MASK_ALT, MOD_MASK_ALT, (char_u)'A'}, 2250 {0, 0, NUL} 2251 /* NOTE: when adding an entry, update MAX_KEY_NAME_LEN! */ 2252 }; 2253 2254 /* 2255 * Shifted key terminal codes and their unshifted equivalent. 2256 * Don't add mouse codes here, they are handled separately! 2257 */ 2258 #define MOD_KEYS_ENTRY_SIZE 5 2259 2260 static char_u modifier_keys_table[] = 2261 { 2262 /* mod mask with modifier without modifier */ 2263 MOD_MASK_SHIFT, '&', '9', '@', '1', /* begin */ 2264 MOD_MASK_SHIFT, '&', '0', '@', '2', /* cancel */ 2265 MOD_MASK_SHIFT, '*', '1', '@', '4', /* command */ 2266 MOD_MASK_SHIFT, '*', '2', '@', '5', /* copy */ 2267 MOD_MASK_SHIFT, '*', '3', '@', '6', /* create */ 2268 MOD_MASK_SHIFT, '*', '4', 'k', 'D', /* delete char */ 2269 MOD_MASK_SHIFT, '*', '5', 'k', 'L', /* delete line */ 2270 MOD_MASK_SHIFT, '*', '7', '@', '7', /* end */ 2271 MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_END, '@', '7', /* end */ 2272 MOD_MASK_SHIFT, '*', '9', '@', '9', /* exit */ 2273 MOD_MASK_SHIFT, '*', '0', '@', '0', /* find */ 2274 MOD_MASK_SHIFT, '#', '1', '%', '1', /* help */ 2275 MOD_MASK_SHIFT, '#', '2', 'k', 'h', /* home */ 2276 MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_HOME, 'k', 'h', /* home */ 2277 MOD_MASK_SHIFT, '#', '3', 'k', 'I', /* insert */ 2278 MOD_MASK_SHIFT, '#', '4', 'k', 'l', /* left arrow */ 2279 MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_LEFT, 'k', 'l', /* left arrow */ 2280 MOD_MASK_SHIFT, '%', 'a', '%', '3', /* message */ 2281 MOD_MASK_SHIFT, '%', 'b', '%', '4', /* move */ 2282 MOD_MASK_SHIFT, '%', 'c', '%', '5', /* next */ 2283 MOD_MASK_SHIFT, '%', 'd', '%', '7', /* options */ 2284 MOD_MASK_SHIFT, '%', 'e', '%', '8', /* previous */ 2285 MOD_MASK_SHIFT, '%', 'f', '%', '9', /* print */ 2286 MOD_MASK_SHIFT, '%', 'g', '%', '0', /* redo */ 2287 MOD_MASK_SHIFT, '%', 'h', '&', '3', /* replace */ 2288 MOD_MASK_SHIFT, '%', 'i', 'k', 'r', /* right arr. */ 2289 MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_RIGHT, 'k', 'r', /* right arr. */ 2290 MOD_MASK_SHIFT, '%', 'j', '&', '5', /* resume */ 2291 MOD_MASK_SHIFT, '!', '1', '&', '6', /* save */ 2292 MOD_MASK_SHIFT, '!', '2', '&', '7', /* suspend */ 2293 MOD_MASK_SHIFT, '!', '3', '&', '8', /* undo */ 2294 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_UP, 'k', 'u', /* up arrow */ 2295 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_DOWN, 'k', 'd', /* down arrow */ 2296 2297 /* vt100 F1 */ 2298 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF1, KS_EXTRA, (int)KE_XF1, 2299 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF2, KS_EXTRA, (int)KE_XF2, 2300 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF3, KS_EXTRA, (int)KE_XF3, 2301 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF4, KS_EXTRA, (int)KE_XF4, 2302 2303 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F1, 'k', '1', /* F1 */ 2304 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F2, 'k', '2', 2305 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F3, 'k', '3', 2306 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F4, 'k', '4', 2307 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F5, 'k', '5', 2308 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F6, 'k', '6', 2309 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F7, 'k', '7', 2310 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F8, 'k', '8', 2311 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F9, 'k', '9', 2312 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F10, 'k', ';', /* F10 */ 2313 2314 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F11, 'F', '1', 2315 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F12, 'F', '2', 2316 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F13, 'F', '3', 2317 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F14, 'F', '4', 2318 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F15, 'F', '5', 2319 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F16, 'F', '6', 2320 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F17, 'F', '7', 2321 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F18, 'F', '8', 2322 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F19, 'F', '9', 2323 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F20, 'F', 'A', 2324 2325 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F21, 'F', 'B', 2326 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F22, 'F', 'C', 2327 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F23, 'F', 'D', 2328 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F24, 'F', 'E', 2329 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F25, 'F', 'F', 2330 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F26, 'F', 'G', 2331 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F27, 'F', 'H', 2332 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F28, 'F', 'I', 2333 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F29, 'F', 'J', 2334 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F30, 'F', 'K', 2335 2336 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F31, 'F', 'L', 2337 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F32, 'F', 'M', 2338 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F33, 'F', 'N', 2339 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F34, 'F', 'O', 2340 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F35, 'F', 'P', 2341 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F36, 'F', 'Q', 2342 MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F37, 'F', 'R', 2343 2344 /* TAB pseudo code*/ 2345 MOD_MASK_SHIFT, 'k', 'B', KS_EXTRA, (int)KE_TAB, 2346 2347 NUL 2348 }; 2349 2350 static struct key_name_entry 2351 { 2352 int key; /* Special key code or ascii value */ 2353 char_u *name; /* Name of key */ 2354 } key_names_table[] = 2355 { 2356 {' ', (char_u *)"Space"}, 2357 {TAB, (char_u *)"Tab"}, 2358 {K_TAB, (char_u *)"Tab"}, 2359 {NL, (char_u *)"NL"}, 2360 {NL, (char_u *)"NewLine"}, /* Alternative name */ 2361 {NL, (char_u *)"LineFeed"}, /* Alternative name */ 2362 {NL, (char_u *)"LF"}, /* Alternative name */ 2363 {CAR, (char_u *)"CR"}, 2364 {CAR, (char_u *)"Return"}, /* Alternative name */ 2365 {CAR, (char_u *)"Enter"}, /* Alternative name */ 2366 {K_BS, (char_u *)"BS"}, 2367 {K_BS, (char_u *)"BackSpace"}, /* Alternative name */ 2368 {ESC, (char_u *)"Esc"}, 2369 {CSI, (char_u *)"CSI"}, 2370 {K_CSI, (char_u *)"xCSI"}, 2371 {'|', (char_u *)"Bar"}, 2372 {'\\', (char_u *)"Bslash"}, 2373 {K_DEL, (char_u *)"Del"}, 2374 {K_DEL, (char_u *)"Delete"}, /* Alternative name */ 2375 {K_KDEL, (char_u *)"kDel"}, 2376 {K_UP, (char_u *)"Up"}, 2377 {K_DOWN, (char_u *)"Down"}, 2378 {K_LEFT, (char_u *)"Left"}, 2379 {K_RIGHT, (char_u *)"Right"}, 2380 {K_XUP, (char_u *)"xUp"}, 2381 {K_XDOWN, (char_u *)"xDown"}, 2382 {K_XLEFT, (char_u *)"xLeft"}, 2383 {K_XRIGHT, (char_u *)"xRight"}, 2384 {K_PS, (char_u *)"PasteStart"}, 2385 {K_PE, (char_u *)"PasteEnd"}, 2386 2387 {K_F1, (char_u *)"F1"}, 2388 {K_F2, (char_u *)"F2"}, 2389 {K_F3, (char_u *)"F3"}, 2390 {K_F4, (char_u *)"F4"}, 2391 {K_F5, (char_u *)"F5"}, 2392 {K_F6, (char_u *)"F6"}, 2393 {K_F7, (char_u *)"F7"}, 2394 {K_F8, (char_u *)"F8"}, 2395 {K_F9, (char_u *)"F9"}, 2396 {K_F10, (char_u *)"F10"}, 2397 2398 {K_F11, (char_u *)"F11"}, 2399 {K_F12, (char_u *)"F12"}, 2400 {K_F13, (char_u *)"F13"}, 2401 {K_F14, (char_u *)"F14"}, 2402 {K_F15, (char_u *)"F15"}, 2403 {K_F16, (char_u *)"F16"}, 2404 {K_F17, (char_u *)"F17"}, 2405 {K_F18, (char_u *)"F18"}, 2406 {K_F19, (char_u *)"F19"}, 2407 {K_F20, (char_u *)"F20"}, 2408 2409 {K_F21, (char_u *)"F21"}, 2410 {K_F22, (char_u *)"F22"}, 2411 {K_F23, (char_u *)"F23"}, 2412 {K_F24, (char_u *)"F24"}, 2413 {K_F25, (char_u *)"F25"}, 2414 {K_F26, (char_u *)"F26"}, 2415 {K_F27, (char_u *)"F27"}, 2416 {K_F28, (char_u *)"F28"}, 2417 {K_F29, (char_u *)"F29"}, 2418 {K_F30, (char_u *)"F30"}, 2419 2420 {K_F31, (char_u *)"F31"}, 2421 {K_F32, (char_u *)"F32"}, 2422 {K_F33, (char_u *)"F33"}, 2423 {K_F34, (char_u *)"F34"}, 2424 {K_F35, (char_u *)"F35"}, 2425 {K_F36, (char_u *)"F36"}, 2426 {K_F37, (char_u *)"F37"}, 2427 2428 {K_XF1, (char_u *)"xF1"}, 2429 {K_XF2, (char_u *)"xF2"}, 2430 {K_XF3, (char_u *)"xF3"}, 2431 {K_XF4, (char_u *)"xF4"}, 2432 2433 {K_HELP, (char_u *)"Help"}, 2434 {K_UNDO, (char_u *)"Undo"}, 2435 {K_INS, (char_u *)"Insert"}, 2436 {K_INS, (char_u *)"Ins"}, /* Alternative name */ 2437 {K_KINS, (char_u *)"kInsert"}, 2438 {K_HOME, (char_u *)"Home"}, 2439 {K_KHOME, (char_u *)"kHome"}, 2440 {K_XHOME, (char_u *)"xHome"}, 2441 {K_ZHOME, (char_u *)"zHome"}, 2442 {K_END, (char_u *)"End"}, 2443 {K_KEND, (char_u *)"kEnd"}, 2444 {K_XEND, (char_u *)"xEnd"}, 2445 {K_ZEND, (char_u *)"zEnd"}, 2446 {K_PAGEUP, (char_u *)"PageUp"}, 2447 {K_PAGEDOWN, (char_u *)"PageDown"}, 2448 {K_KPAGEUP, (char_u *)"kPageUp"}, 2449 {K_KPAGEDOWN, (char_u *)"kPageDown"}, 2450 2451 {K_KPLUS, (char_u *)"kPlus"}, 2452 {K_KMINUS, (char_u *)"kMinus"}, 2453 {K_KDIVIDE, (char_u *)"kDivide"}, 2454 {K_KMULTIPLY, (char_u *)"kMultiply"}, 2455 {K_KENTER, (char_u *)"kEnter"}, 2456 {K_KPOINT, (char_u *)"kPoint"}, 2457 2458 {K_K0, (char_u *)"k0"}, 2459 {K_K1, (char_u *)"k1"}, 2460 {K_K2, (char_u *)"k2"}, 2461 {K_K3, (char_u *)"k3"}, 2462 {K_K4, (char_u *)"k4"}, 2463 {K_K5, (char_u *)"k5"}, 2464 {K_K6, (char_u *)"k6"}, 2465 {K_K7, (char_u *)"k7"}, 2466 {K_K8, (char_u *)"k8"}, 2467 {K_K9, (char_u *)"k9"}, 2468 2469 {'<', (char_u *)"lt"}, 2470 2471 {K_MOUSE, (char_u *)"Mouse"}, 2472 #ifdef FEAT_MOUSE_NET 2473 {K_NETTERM_MOUSE, (char_u *)"NetMouse"}, 2474 #endif 2475 #ifdef FEAT_MOUSE_DEC 2476 {K_DEC_MOUSE, (char_u *)"DecMouse"}, 2477 #endif 2478 #ifdef FEAT_MOUSE_JSB 2479 {K_JSBTERM_MOUSE, (char_u *)"JsbMouse"}, 2480 #endif 2481 #ifdef FEAT_MOUSE_PTERM 2482 {K_PTERM_MOUSE, (char_u *)"PtermMouse"}, 2483 #endif 2484 #ifdef FEAT_MOUSE_URXVT 2485 {K_URXVT_MOUSE, (char_u *)"UrxvtMouse"}, 2486 #endif 2487 #ifdef FEAT_MOUSE_SGR 2488 {K_SGR_MOUSE, (char_u *)"SgrMouse"}, 2489 {K_SGR_MOUSERELEASE, (char_u *)"SgrMouseRelelase"}, 2490 #endif 2491 {K_LEFTMOUSE, (char_u *)"LeftMouse"}, 2492 {K_LEFTMOUSE_NM, (char_u *)"LeftMouseNM"}, 2493 {K_LEFTDRAG, (char_u *)"LeftDrag"}, 2494 {K_LEFTRELEASE, (char_u *)"LeftRelease"}, 2495 {K_LEFTRELEASE_NM, (char_u *)"LeftReleaseNM"}, 2496 {K_MOUSEMOVE, (char_u *)"MouseMove"}, 2497 {K_MIDDLEMOUSE, (char_u *)"MiddleMouse"}, 2498 {K_MIDDLEDRAG, (char_u *)"MiddleDrag"}, 2499 {K_MIDDLERELEASE, (char_u *)"MiddleRelease"}, 2500 {K_RIGHTMOUSE, (char_u *)"RightMouse"}, 2501 {K_RIGHTDRAG, (char_u *)"RightDrag"}, 2502 {K_RIGHTRELEASE, (char_u *)"RightRelease"}, 2503 {K_MOUSEDOWN, (char_u *)"ScrollWheelUp"}, 2504 {K_MOUSEUP, (char_u *)"ScrollWheelDown"}, 2505 {K_MOUSELEFT, (char_u *)"ScrollWheelRight"}, 2506 {K_MOUSERIGHT, (char_u *)"ScrollWheelLeft"}, 2507 {K_MOUSEDOWN, (char_u *)"MouseDown"}, /* OBSOLETE: Use */ 2508 {K_MOUSEUP, (char_u *)"MouseUp"}, /* ScrollWheelXXX instead */ 2509 {K_X1MOUSE, (char_u *)"X1Mouse"}, 2510 {K_X1DRAG, (char_u *)"X1Drag"}, 2511 {K_X1RELEASE, (char_u *)"X1Release"}, 2512 {K_X2MOUSE, (char_u *)"X2Mouse"}, 2513 {K_X2DRAG, (char_u *)"X2Drag"}, 2514 {K_X2RELEASE, (char_u *)"X2Release"}, 2515 {K_DROP, (char_u *)"Drop"}, 2516 {K_ZERO, (char_u *)"Nul"}, 2517 #ifdef FEAT_EVAL 2518 {K_SNR, (char_u *)"SNR"}, 2519 #endif 2520 {K_PLUG, (char_u *)"Plug"}, 2521 {K_CURSORHOLD, (char_u *)"CursorHold"}, 2522 {0, NULL} 2523 /* NOTE: When adding a long name update MAX_KEY_NAME_LEN. */ 2524 }; 2525 2526 #define KEY_NAMES_TABLE_LEN (sizeof(key_names_table) / sizeof(struct key_name_entry)) 2527 2528 #ifdef FEAT_MOUSE 2529 static struct mousetable 2530 { 2531 int pseudo_code; /* Code for pseudo mouse event */ 2532 int button; /* Which mouse button is it? */ 2533 int is_click; /* Is it a mouse button click event? */ 2534 int is_drag; /* Is it a mouse drag event? */ 2535 } mouse_table[] = 2536 { 2537 {(int)KE_LEFTMOUSE, MOUSE_LEFT, TRUE, FALSE}, 2538 #ifdef FEAT_GUI 2539 {(int)KE_LEFTMOUSE_NM, MOUSE_LEFT, TRUE, FALSE}, 2540 #endif 2541 {(int)KE_LEFTDRAG, MOUSE_LEFT, FALSE, TRUE}, 2542 {(int)KE_LEFTRELEASE, MOUSE_LEFT, FALSE, FALSE}, 2543 #ifdef FEAT_GUI 2544 {(int)KE_LEFTRELEASE_NM, MOUSE_LEFT, FALSE, FALSE}, 2545 #endif 2546 {(int)KE_MIDDLEMOUSE, MOUSE_MIDDLE, TRUE, FALSE}, 2547 {(int)KE_MIDDLEDRAG, MOUSE_MIDDLE, FALSE, TRUE}, 2548 {(int)KE_MIDDLERELEASE, MOUSE_MIDDLE, FALSE, FALSE}, 2549 {(int)KE_RIGHTMOUSE, MOUSE_RIGHT, TRUE, FALSE}, 2550 {(int)KE_RIGHTDRAG, MOUSE_RIGHT, FALSE, TRUE}, 2551 {(int)KE_RIGHTRELEASE, MOUSE_RIGHT, FALSE, FALSE}, 2552 {(int)KE_X1MOUSE, MOUSE_X1, TRUE, FALSE}, 2553 {(int)KE_X1DRAG, MOUSE_X1, FALSE, TRUE}, 2554 {(int)KE_X1RELEASE, MOUSE_X1, FALSE, FALSE}, 2555 {(int)KE_X2MOUSE, MOUSE_X2, TRUE, FALSE}, 2556 {(int)KE_X2DRAG, MOUSE_X2, FALSE, TRUE}, 2557 {(int)KE_X2RELEASE, MOUSE_X2, FALSE, FALSE}, 2558 /* DRAG without CLICK */ 2559 {(int)KE_MOUSEMOVE, MOUSE_RELEASE, FALSE, TRUE}, 2560 /* RELEASE without CLICK */ 2561 {(int)KE_IGNORE, MOUSE_RELEASE, FALSE, FALSE}, 2562 {0, 0, 0, 0}, 2563 }; 2564 #endif /* FEAT_MOUSE */ 2565 2566 /* 2567 * Return the modifier mask bit (MOD_MASK_*) which corresponds to the given 2568 * modifier name ('S' for Shift, 'C' for Ctrl etc). 2569 */ 2570 int 2571 name_to_mod_mask(int c) 2572 { 2573 int i; 2574 2575 c = TOUPPER_ASC(c); 2576 for (i = 0; mod_mask_table[i].mod_mask != 0; i++) 2577 if (c == mod_mask_table[i].name) 2578 return mod_mask_table[i].mod_flag; 2579 return 0; 2580 } 2581 2582 /* 2583 * Check if if there is a special key code for "key" that includes the 2584 * modifiers specified. 2585 */ 2586 int 2587 simplify_key(int key, int *modifiers) 2588 { 2589 int i; 2590 int key0; 2591 int key1; 2592 2593 if (*modifiers & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT)) 2594 { 2595 /* TAB is a special case */ 2596 if (key == TAB && (*modifiers & MOD_MASK_SHIFT)) 2597 { 2598 *modifiers &= ~MOD_MASK_SHIFT; 2599 return K_S_TAB; 2600 } 2601 key0 = KEY2TERMCAP0(key); 2602 key1 = KEY2TERMCAP1(key); 2603 for (i = 0; modifier_keys_table[i] != NUL; i += MOD_KEYS_ENTRY_SIZE) 2604 if (key0 == modifier_keys_table[i + 3] 2605 && key1 == modifier_keys_table[i + 4] 2606 && (*modifiers & modifier_keys_table[i])) 2607 { 2608 *modifiers &= ~modifier_keys_table[i]; 2609 return TERMCAP2KEY(modifier_keys_table[i + 1], 2610 modifier_keys_table[i + 2]); 2611 } 2612 } 2613 return key; 2614 } 2615 2616 /* 2617 * Change <xHome> to <Home>, <xUp> to <Up>, etc. 2618 */ 2619 int 2620 handle_x_keys(int key) 2621 { 2622 switch (key) 2623 { 2624 case K_XUP: return K_UP; 2625 case K_XDOWN: return K_DOWN; 2626 case K_XLEFT: return K_LEFT; 2627 case K_XRIGHT: return K_RIGHT; 2628 case K_XHOME: return K_HOME; 2629 case K_ZHOME: return K_HOME; 2630 case K_XEND: return K_END; 2631 case K_ZEND: return K_END; 2632 case K_XF1: return K_F1; 2633 case K_XF2: return K_F2; 2634 case K_XF3: return K_F3; 2635 case K_XF4: return K_F4; 2636 case K_S_XF1: return K_S_F1; 2637 case K_S_XF2: return K_S_F2; 2638 case K_S_XF3: return K_S_F3; 2639 case K_S_XF4: return K_S_F4; 2640 } 2641 return key; 2642 } 2643 2644 /* 2645 * Return a string which contains the name of the given key when the given 2646 * modifiers are down. 2647 */ 2648 char_u * 2649 get_special_key_name(int c, int modifiers) 2650 { 2651 static char_u string[MAX_KEY_NAME_LEN + 1]; 2652 2653 int i, idx; 2654 int table_idx; 2655 char_u *s; 2656 2657 string[0] = '<'; 2658 idx = 1; 2659 2660 /* Key that stands for a normal character. */ 2661 if (IS_SPECIAL(c) && KEY2TERMCAP0(c) == KS_KEY) 2662 c = KEY2TERMCAP1(c); 2663 2664 /* 2665 * Translate shifted special keys into unshifted keys and set modifier. 2666 * Same for CTRL and ALT modifiers. 2667 */ 2668 if (IS_SPECIAL(c)) 2669 { 2670 for (i = 0; modifier_keys_table[i] != 0; i += MOD_KEYS_ENTRY_SIZE) 2671 if ( KEY2TERMCAP0(c) == (int)modifier_keys_table[i + 1] 2672 && (int)KEY2TERMCAP1(c) == (int)modifier_keys_table[i + 2]) 2673 { 2674 modifiers |= modifier_keys_table[i]; 2675 c = TERMCAP2KEY(modifier_keys_table[i + 3], 2676 modifier_keys_table[i + 4]); 2677 break; 2678 } 2679 } 2680 2681 /* try to find the key in the special key table */ 2682 table_idx = find_special_key_in_table(c); 2683 2684 /* 2685 * When not a known special key, and not a printable character, try to 2686 * extract modifiers. 2687 */ 2688 if (c > 0 2689 #ifdef FEAT_MBYTE 2690 && (*mb_char2len)(c) == 1 2691 #endif 2692 ) 2693 { 2694 if (table_idx < 0 2695 && (!vim_isprintc(c) || (c & 0x7f) == ' ') 2696 && (c & 0x80)) 2697 { 2698 c &= 0x7f; 2699 modifiers |= MOD_MASK_ALT; 2700 /* try again, to find the un-alted key in the special key table */ 2701 table_idx = find_special_key_in_table(c); 2702 } 2703 if (table_idx < 0 && !vim_isprintc(c) && c < ' ') 2704 { 2705 #ifdef EBCDIC 2706 c = CtrlChar(c); 2707 #else 2708 c += '@'; 2709 #endif 2710 modifiers |= MOD_MASK_CTRL; 2711 } 2712 } 2713 2714 /* translate the modifier into a string */ 2715 for (i = 0; mod_mask_table[i].name != 'A'; i++) 2716 if ((modifiers & mod_mask_table[i].mod_mask) 2717 == mod_mask_table[i].mod_flag) 2718 { 2719 string[idx++] = mod_mask_table[i].name; 2720 string[idx++] = (char_u)'-'; 2721 } 2722 2723 if (table_idx < 0) /* unknown special key, may output t_xx */ 2724 { 2725 if (IS_SPECIAL(c)) 2726 { 2727 string[idx++] = 't'; 2728 string[idx++] = '_'; 2729 string[idx++] = KEY2TERMCAP0(c); 2730 string[idx++] = KEY2TERMCAP1(c); 2731 } 2732 /* Not a special key, only modifiers, output directly */ 2733 else 2734 { 2735 #ifdef FEAT_MBYTE 2736 if (has_mbyte && (*mb_char2len)(c) > 1) 2737 idx += (*mb_char2bytes)(c, string + idx); 2738 else 2739 #endif 2740 if (vim_isprintc(c)) 2741 string[idx++] = c; 2742 else 2743 { 2744 s = transchar(c); 2745 while (*s) 2746 string[idx++] = *s++; 2747 } 2748 } 2749 } 2750 else /* use name of special key */ 2751 { 2752 size_t len = STRLEN(key_names_table[table_idx].name); 2753 2754 if (len + idx + 2 <= MAX_KEY_NAME_LEN) 2755 { 2756 STRCPY(string + idx, key_names_table[table_idx].name); 2757 idx += (int)len; 2758 } 2759 } 2760 string[idx++] = '>'; 2761 string[idx] = NUL; 2762 return string; 2763 } 2764 2765 /* 2766 * Try translating a <> name at (*srcp)[] to dst[]. 2767 * Return the number of characters added to dst[], zero for no match. 2768 * If there is a match, srcp is advanced to after the <> name. 2769 * dst[] must be big enough to hold the result (up to six characters)! 2770 */ 2771 int 2772 trans_special( 2773 char_u **srcp, 2774 char_u *dst, 2775 int keycode, /* prefer key code, e.g. K_DEL instead of DEL */ 2776 int in_string) /* TRUE when inside a double quoted string */ 2777 { 2778 int modifiers = 0; 2779 int key; 2780 int dlen = 0; 2781 2782 key = find_special_key(srcp, &modifiers, keycode, FALSE, in_string); 2783 if (key == 0) 2784 return 0; 2785 2786 /* Put the appropriate modifier in a string */ 2787 if (modifiers != 0) 2788 { 2789 dst[dlen++] = K_SPECIAL; 2790 dst[dlen++] = KS_MODIFIER; 2791 dst[dlen++] = modifiers; 2792 } 2793 2794 if (IS_SPECIAL(key)) 2795 { 2796 dst[dlen++] = K_SPECIAL; 2797 dst[dlen++] = KEY2TERMCAP0(key); 2798 dst[dlen++] = KEY2TERMCAP1(key); 2799 } 2800 #ifdef FEAT_MBYTE 2801 else if (has_mbyte && !keycode) 2802 dlen += (*mb_char2bytes)(key, dst + dlen); 2803 #endif 2804 else if (keycode) 2805 dlen = (int)(add_char2buf(key, dst + dlen) - dst); 2806 else 2807 dst[dlen++] = key; 2808 2809 return dlen; 2810 } 2811 2812 /* 2813 * Try translating a <> name at (*srcp)[], return the key and modifiers. 2814 * srcp is advanced to after the <> name. 2815 * returns 0 if there is no match. 2816 */ 2817 int 2818 find_special_key( 2819 char_u **srcp, 2820 int *modp, 2821 int keycode, /* prefer key code, e.g. K_DEL instead of DEL */ 2822 int keep_x_key, /* don't translate xHome to Home key */ 2823 int in_string) /* TRUE in string, double quote is escaped */ 2824 { 2825 char_u *last_dash; 2826 char_u *end_of_name; 2827 char_u *src; 2828 char_u *bp; 2829 int modifiers; 2830 int bit; 2831 int key; 2832 uvarnumber_T n; 2833 int l; 2834 2835 src = *srcp; 2836 if (src[0] != '<') 2837 return 0; 2838 2839 /* Find end of modifier list */ 2840 last_dash = src; 2841 for (bp = src + 1; *bp == '-' || vim_isIDc(*bp); bp++) 2842 { 2843 if (*bp == '-') 2844 { 2845 last_dash = bp; 2846 if (bp[1] != NUL) 2847 { 2848 #ifdef FEAT_MBYTE 2849 if (has_mbyte) 2850 l = mb_ptr2len(bp + 1); 2851 else 2852 #endif 2853 l = 1; 2854 /* Anything accepted, like <C-?>. 2855 * <C-"> or <M-"> are not special in strings as " is 2856 * the string delimiter. With a backslash it works: <M-\"> */ 2857 if (!(in_string && bp[1] == '"') && bp[2] == '>') 2858 bp += l; 2859 else if (in_string && bp[1] == '\\' && bp[2] == '"' 2860 && bp[3] == '>') 2861 bp += 2; 2862 } 2863 } 2864 if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3]) 2865 bp += 3; /* skip t_xx, xx may be '-' or '>' */ 2866 else if (STRNICMP(bp, "char-", 5) == 0) 2867 { 2868 vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0); 2869 bp += l + 5; 2870 break; 2871 } 2872 } 2873 2874 if (*bp == '>') /* found matching '>' */ 2875 { 2876 end_of_name = bp + 1; 2877 2878 /* Which modifiers are given? */ 2879 modifiers = 0x0; 2880 for (bp = src + 1; bp < last_dash; bp++) 2881 { 2882 if (*bp != '-') 2883 { 2884 bit = name_to_mod_mask(*bp); 2885 if (bit == 0x0) 2886 break; /* Illegal modifier name */ 2887 modifiers |= bit; 2888 } 2889 } 2890 2891 /* 2892 * Legal modifier name. 2893 */ 2894 if (bp >= last_dash) 2895 { 2896 if (STRNICMP(last_dash + 1, "char-", 5) == 0 2897 && VIM_ISDIGIT(last_dash[6])) 2898 { 2899 /* <Char-123> or <Char-033> or <Char-0x33> */ 2900 vim_str2nr(last_dash + 6, NULL, NULL, STR2NR_ALL, NULL, &n, 0); 2901 key = (int)n; 2902 } 2903 else 2904 { 2905 int off = 1; 2906 2907 /* Modifier with single letter, or special key name. */ 2908 if (in_string && last_dash[1] == '\\' && last_dash[2] == '"') 2909 off = 2; 2910 #ifdef FEAT_MBYTE 2911 if (has_mbyte) 2912 l = mb_ptr2len(last_dash + off); 2913 else 2914 #endif 2915 l = 1; 2916 if (modifiers != 0 && last_dash[l + off] == '>') 2917 key = PTR2CHAR(last_dash + off); 2918 else 2919 { 2920 key = get_special_key_code(last_dash + off); 2921 if (!keep_x_key) 2922 key = handle_x_keys(key); 2923 } 2924 } 2925 2926 /* 2927 * get_special_key_code() may return NUL for invalid 2928 * special key name. 2929 */ 2930 if (key != NUL) 2931 { 2932 /* 2933 * Only use a modifier when there is no special key code that 2934 * includes the modifier. 2935 */ 2936 key = simplify_key(key, &modifiers); 2937 2938 if (!keycode) 2939 { 2940 /* don't want keycode, use single byte code */ 2941 if (key == K_BS) 2942 key = BS; 2943 else if (key == K_DEL || key == K_KDEL) 2944 key = DEL; 2945 } 2946 2947 /* 2948 * Normal Key with modifier: Try to make a single byte code. 2949 */ 2950 if (!IS_SPECIAL(key)) 2951 key = extract_modifiers(key, &modifiers); 2952 2953 *modp = modifiers; 2954 *srcp = end_of_name; 2955 return key; 2956 } 2957 } 2958 } 2959 return 0; 2960 } 2961 2962 /* 2963 * Try to include modifiers in the key. 2964 * Changes "Shift-a" to 'A', "Alt-A" to 0xc0, etc. 2965 */ 2966 int 2967 extract_modifiers(int key, int *modp) 2968 { 2969 int modifiers = *modp; 2970 2971 #ifdef MACOS_X 2972 /* Command-key really special, no fancynest */ 2973 if (!(modifiers & MOD_MASK_CMD)) 2974 #endif 2975 if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key)) 2976 { 2977 key = TOUPPER_ASC(key); 2978 modifiers &= ~MOD_MASK_SHIFT; 2979 } 2980 if ((modifiers & MOD_MASK_CTRL) 2981 #ifdef EBCDIC 2982 /* * TODO: EBCDIC Better use: 2983 * && (Ctrl_chr(key) || key == '?') 2984 * ??? */ 2985 && strchr("?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_", key) 2986 != NULL 2987 #else 2988 && ((key >= '?' && key <= '_') || ASCII_ISALPHA(key)) 2989 #endif 2990 ) 2991 { 2992 key = Ctrl_chr(key); 2993 modifiers &= ~MOD_MASK_CTRL; 2994 /* <C-@> is <Nul> */ 2995 if (key == 0) 2996 key = K_ZERO; 2997 } 2998 #ifdef MACOS_X 2999 /* Command-key really special, no fancynest */ 3000 if (!(modifiers & MOD_MASK_CMD)) 3001 #endif 3002 if ((modifiers & MOD_MASK_ALT) && key < 0x80 3003 #ifdef FEAT_MBYTE 3004 && !enc_dbcs /* avoid creating a lead byte */ 3005 #endif 3006 ) 3007 { 3008 key |= 0x80; 3009 modifiers &= ~MOD_MASK_ALT; /* remove the META modifier */ 3010 } 3011 3012 *modp = modifiers; 3013 return key; 3014 } 3015 3016 /* 3017 * Try to find key "c" in the special key table. 3018 * Return the index when found, -1 when not found. 3019 */ 3020 int 3021 find_special_key_in_table(int c) 3022 { 3023 int i; 3024 3025 for (i = 0; key_names_table[i].name != NULL; i++) 3026 if (c == key_names_table[i].key) 3027 break; 3028 if (key_names_table[i].name == NULL) 3029 i = -1; 3030 return i; 3031 } 3032 3033 /* 3034 * Find the special key with the given name (the given string does not have to 3035 * end with NUL, the name is assumed to end before the first non-idchar). 3036 * If the name starts with "t_" the next two characters are interpreted as a 3037 * termcap name. 3038 * Return the key code, or 0 if not found. 3039 */ 3040 int 3041 get_special_key_code(char_u *name) 3042 { 3043 char_u *table_name; 3044 char_u string[3]; 3045 int i, j; 3046 3047 /* 3048 * If it's <t_xx> we get the code for xx from the termcap 3049 */ 3050 if (name[0] == 't' && name[1] == '_' && name[2] != NUL && name[3] != NUL) 3051 { 3052 string[0] = name[2]; 3053 string[1] = name[3]; 3054 string[2] = NUL; 3055 if (add_termcap_entry(string, FALSE) == OK) 3056 return TERMCAP2KEY(name[2], name[3]); 3057 } 3058 else 3059 for (i = 0; key_names_table[i].name != NULL; i++) 3060 { 3061 table_name = key_names_table[i].name; 3062 for (j = 0; vim_isIDc(name[j]) && table_name[j] != NUL; j++) 3063 if (TOLOWER_ASC(table_name[j]) != TOLOWER_ASC(name[j])) 3064 break; 3065 if (!vim_isIDc(name[j]) && table_name[j] == NUL) 3066 return key_names_table[i].key; 3067 } 3068 return 0; 3069 } 3070 3071 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 3072 char_u * 3073 get_key_name(int i) 3074 { 3075 if (i >= (int)KEY_NAMES_TABLE_LEN) 3076 return NULL; 3077 return key_names_table[i].name; 3078 } 3079 #endif 3080 3081 #if defined(FEAT_MOUSE) || defined(PROTO) 3082 /* 3083 * Look up the given mouse code to return the relevant information in the other 3084 * arguments. Return which button is down or was released. 3085 */ 3086 int 3087 get_mouse_button(int code, int *is_click, int *is_drag) 3088 { 3089 int i; 3090 3091 for (i = 0; mouse_table[i].pseudo_code; i++) 3092 if (code == mouse_table[i].pseudo_code) 3093 { 3094 *is_click = mouse_table[i].is_click; 3095 *is_drag = mouse_table[i].is_drag; 3096 return mouse_table[i].button; 3097 } 3098 return 0; /* Shouldn't get here */ 3099 } 3100 3101 /* 3102 * Return the appropriate pseudo mouse event token (KE_LEFTMOUSE etc) based on 3103 * the given information about which mouse button is down, and whether the 3104 * mouse was clicked, dragged or released. 3105 */ 3106 int 3107 get_pseudo_mouse_code( 3108 int button, /* eg MOUSE_LEFT */ 3109 int is_click, 3110 int is_drag) 3111 { 3112 int i; 3113 3114 for (i = 0; mouse_table[i].pseudo_code; i++) 3115 if (button == mouse_table[i].button 3116 && is_click == mouse_table[i].is_click 3117 && is_drag == mouse_table[i].is_drag) 3118 { 3119 #ifdef FEAT_GUI 3120 /* Trick: a non mappable left click and release has mouse_col -1 3121 * or added MOUSE_COLOFF. Used for 'mousefocus' in 3122 * gui_mouse_moved() */ 3123 if (mouse_col < 0 || mouse_col > MOUSE_COLOFF) 3124 { 3125 if (mouse_col < 0) 3126 mouse_col = 0; 3127 else 3128 mouse_col -= MOUSE_COLOFF; 3129 if (mouse_table[i].pseudo_code == (int)KE_LEFTMOUSE) 3130 return (int)KE_LEFTMOUSE_NM; 3131 if (mouse_table[i].pseudo_code == (int)KE_LEFTRELEASE) 3132 return (int)KE_LEFTRELEASE_NM; 3133 } 3134 #endif 3135 return mouse_table[i].pseudo_code; 3136 } 3137 return (int)KE_IGNORE; /* not recognized, ignore it */ 3138 } 3139 #endif /* FEAT_MOUSE */ 3140 3141 /* 3142 * Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC. 3143 */ 3144 int 3145 get_fileformat(buf_T *buf) 3146 { 3147 int c = *buf->b_p_ff; 3148 3149 if (buf->b_p_bin || c == 'u') 3150 return EOL_UNIX; 3151 if (c == 'm') 3152 return EOL_MAC; 3153 return EOL_DOS; 3154 } 3155 3156 /* 3157 * Like get_fileformat(), but override 'fileformat' with "p" for "++opt=val" 3158 * argument. 3159 */ 3160 int 3161 get_fileformat_force( 3162 buf_T *buf, 3163 exarg_T *eap) /* can be NULL! */ 3164 { 3165 int c; 3166 3167 if (eap != NULL && eap->force_ff != 0) 3168 c = eap->cmd[eap->force_ff]; 3169 else 3170 { 3171 if ((eap != NULL && eap->force_bin != 0) 3172 ? (eap->force_bin == FORCE_BIN) : buf->b_p_bin) 3173 return EOL_UNIX; 3174 c = *buf->b_p_ff; 3175 } 3176 if (c == 'u') 3177 return EOL_UNIX; 3178 if (c == 'm') 3179 return EOL_MAC; 3180 return EOL_DOS; 3181 } 3182 3183 /* 3184 * Set the current end-of-line type to EOL_DOS, EOL_UNIX or EOL_MAC. 3185 * Sets both 'textmode' and 'fileformat'. 3186 * Note: Does _not_ set global value of 'textmode'! 3187 */ 3188 void 3189 set_fileformat( 3190 int t, 3191 int opt_flags) /* OPT_LOCAL and/or OPT_GLOBAL */ 3192 { 3193 char *p = NULL; 3194 3195 switch (t) 3196 { 3197 case EOL_DOS: 3198 p = FF_DOS; 3199 curbuf->b_p_tx = TRUE; 3200 break; 3201 case EOL_UNIX: 3202 p = FF_UNIX; 3203 curbuf->b_p_tx = FALSE; 3204 break; 3205 case EOL_MAC: 3206 p = FF_MAC; 3207 curbuf->b_p_tx = FALSE; 3208 break; 3209 } 3210 if (p != NULL) 3211 set_string_option_direct((char_u *)"ff", -1, (char_u *)p, 3212 OPT_FREE | opt_flags, 0); 3213 3214 /* This may cause the buffer to become (un)modified. */ 3215 check_status(curbuf); 3216 redraw_tabline = TRUE; 3217 #ifdef FEAT_TITLE 3218 need_maketitle = TRUE; /* set window title later */ 3219 #endif 3220 } 3221 3222 /* 3223 * Return the default fileformat from 'fileformats'. 3224 */ 3225 int 3226 default_fileformat(void) 3227 { 3228 switch (*p_ffs) 3229 { 3230 case 'm': return EOL_MAC; 3231 case 'd': return EOL_DOS; 3232 } 3233 return EOL_UNIX; 3234 } 3235 3236 /* 3237 * Call shell. Calls mch_call_shell, with 'shellxquote' added. 3238 */ 3239 int 3240 call_shell(char_u *cmd, int opt) 3241 { 3242 char_u *ncmd; 3243 int retval; 3244 #ifdef FEAT_PROFILE 3245 proftime_T wait_time; 3246 #endif 3247 3248 if (p_verbose > 3) 3249 { 3250 verbose_enter(); 3251 smsg((char_u *)_("Calling shell to execute: \"%s\""), 3252 cmd == NULL ? p_sh : cmd); 3253 out_char('\n'); 3254 cursor_on(); 3255 verbose_leave(); 3256 } 3257 3258 #ifdef FEAT_PROFILE 3259 if (do_profiling == PROF_YES) 3260 prof_child_enter(&wait_time); 3261 #endif 3262 3263 if (*p_sh == NUL) 3264 { 3265 EMSG(_(e_shellempty)); 3266 retval = -1; 3267 } 3268 else 3269 { 3270 #ifdef FEAT_GUI_MSWIN 3271 /* Don't hide the pointer while executing a shell command. */ 3272 gui_mch_mousehide(FALSE); 3273 #endif 3274 #ifdef FEAT_GUI 3275 ++hold_gui_events; 3276 #endif 3277 /* The external command may update a tags file, clear cached tags. */ 3278 tag_freematch(); 3279 3280 if (cmd == NULL || *p_sxq == NUL) 3281 retval = mch_call_shell(cmd, opt); 3282 else 3283 { 3284 char_u *ecmd = cmd; 3285 3286 if (*p_sxe != NUL && STRCMP(p_sxq, "(") == 0) 3287 { 3288 ecmd = vim_strsave_escaped_ext(cmd, p_sxe, '^', FALSE); 3289 if (ecmd == NULL) 3290 ecmd = cmd; 3291 } 3292 ncmd = alloc((unsigned)(STRLEN(ecmd) + STRLEN(p_sxq) * 2 + 1)); 3293 if (ncmd != NULL) 3294 { 3295 STRCPY(ncmd, p_sxq); 3296 STRCAT(ncmd, ecmd); 3297 /* When 'shellxquote' is ( append ). 3298 * When 'shellxquote' is "( append )". */ 3299 STRCAT(ncmd, STRCMP(p_sxq, "(") == 0 ? (char_u *)")" 3300 : STRCMP(p_sxq, "\"(") == 0 ? (char_u *)")\"" 3301 : p_sxq); 3302 retval = mch_call_shell(ncmd, opt); 3303 vim_free(ncmd); 3304 } 3305 else 3306 retval = -1; 3307 if (ecmd != cmd) 3308 vim_free(ecmd); 3309 } 3310 #ifdef FEAT_GUI 3311 --hold_gui_events; 3312 #endif 3313 /* 3314 * Check the window size, in case it changed while executing the 3315 * external command. 3316 */ 3317 shell_resized_check(); 3318 } 3319 3320 #ifdef FEAT_EVAL 3321 set_vim_var_nr(VV_SHELL_ERROR, (long)retval); 3322 # ifdef FEAT_PROFILE 3323 if (do_profiling == PROF_YES) 3324 prof_child_exit(&wait_time); 3325 # endif 3326 #endif 3327 3328 return retval; 3329 } 3330 3331 /* 3332 * VISUAL, SELECTMODE and OP_PENDING State are never set, they are equal to 3333 * NORMAL State with a condition. This function returns the real State. 3334 */ 3335 int 3336 get_real_state(void) 3337 { 3338 if (State & NORMAL) 3339 { 3340 if (VIsual_active) 3341 { 3342 if (VIsual_select) 3343 return SELECTMODE; 3344 return VISUAL; 3345 } 3346 else if (finish_op) 3347 return OP_PENDING; 3348 } 3349 return State; 3350 } 3351 3352 #if defined(FEAT_MBYTE) || defined(PROTO) 3353 /* 3354 * Return TRUE if "p" points to just after a path separator. 3355 * Takes care of multi-byte characters. 3356 * "b" must point to the start of the file name 3357 */ 3358 int 3359 after_pathsep(char_u *b, char_u *p) 3360 { 3361 return p > b && vim_ispathsep(p[-1]) 3362 && (!has_mbyte || (*mb_head_off)(b, p - 1) == 0); 3363 } 3364 #endif 3365 3366 /* 3367 * Return TRUE if file names "f1" and "f2" are in the same directory. 3368 * "f1" may be a short name, "f2" must be a full path. 3369 */ 3370 int 3371 same_directory(char_u *f1, char_u *f2) 3372 { 3373 char_u ffname[MAXPATHL]; 3374 char_u *t1; 3375 char_u *t2; 3376 3377 /* safety check */ 3378 if (f1 == NULL || f2 == NULL) 3379 return FALSE; 3380 3381 (void)vim_FullName(f1, ffname, MAXPATHL, FALSE); 3382 t1 = gettail_sep(ffname); 3383 t2 = gettail_sep(f2); 3384 return (t1 - ffname == t2 - f2 3385 && pathcmp((char *)ffname, (char *)f2, (int)(t1 - ffname)) == 0); 3386 } 3387 3388 #if defined(FEAT_SESSION) || defined(MSWIN) || defined(FEAT_GUI_MAC) \ 3389 || defined(FEAT_GUI_GTK) \ 3390 || defined(FEAT_SUN_WORKSHOP) || defined(FEAT_NETBEANS_INTG) \ 3391 || defined(PROTO) 3392 /* 3393 * Change to a file's directory. 3394 * Caller must call shorten_fnames()! 3395 * Return OK or FAIL. 3396 */ 3397 int 3398 vim_chdirfile(char_u *fname, char *trigger_autocmd UNUSED) 3399 { 3400 char_u dir[MAXPATHL]; 3401 int res; 3402 3403 vim_strncpy(dir, fname, MAXPATHL - 1); 3404 *gettail_sep(dir) = NUL; 3405 res = mch_chdir((char *)dir) == 0 ? OK : FAIL; 3406 #ifdef FEAT_AUTOCMD 3407 if (res == OK && trigger_autocmd != NULL) 3408 apply_autocmds(EVENT_DIRCHANGED, (char_u *)trigger_autocmd, 3409 dir, FALSE, curbuf); 3410 #endif 3411 return res; 3412 } 3413 #endif 3414 3415 #if defined(STAT_IGNORES_SLASH) || defined(PROTO) 3416 /* 3417 * Check if "name" ends in a slash and is not a directory. 3418 * Used for systems where stat() ignores a trailing slash on a file name. 3419 * The Vim code assumes a trailing slash is only ignored for a directory. 3420 */ 3421 static int 3422 illegal_slash(const char *name) 3423 { 3424 if (name[0] == NUL) 3425 return FALSE; /* no file name is not illegal */ 3426 if (name[strlen(name) - 1] != '/') 3427 return FALSE; /* no trailing slash */ 3428 if (mch_isdir((char_u *)name)) 3429 return FALSE; /* trailing slash for a directory */ 3430 return TRUE; 3431 } 3432 3433 /* 3434 * Special implementation of mch_stat() for Solaris. 3435 */ 3436 int 3437 vim_stat(const char *name, stat_T *stp) 3438 { 3439 /* On Solaris stat() accepts "file/" as if it was "file". Return -1 if 3440 * the name ends in "/" and it's not a directory. */ 3441 return illegal_slash(name) ? -1 : stat(name, stp); 3442 } 3443 #endif 3444 3445 #if defined(CURSOR_SHAPE) || defined(PROTO) 3446 3447 /* 3448 * Handling of cursor and mouse pointer shapes in various modes. 3449 */ 3450 3451 cursorentry_T shape_table[SHAPE_IDX_COUNT] = 3452 { 3453 /* The values will be filled in from the 'guicursor' and 'mouseshape' 3454 * defaults when Vim starts. 3455 * Adjust the SHAPE_IDX_ defines when making changes! */ 3456 {0, 0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE}, 3457 {0, 0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE}, 3458 {0, 0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE}, 3459 {0, 0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE}, 3460 {0, 0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE}, 3461 {0, 0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE}, 3462 {0, 0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE}, 3463 {0, 0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE}, 3464 {0, 0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE}, 3465 {0, 0, 0, 0L, 0L, 0L, 0, 0, "e", SHAPE_MOUSE}, 3466 {0, 0, 0, 0L, 0L, 0L, 0, 0, "s", SHAPE_MOUSE}, 3467 {0, 0, 0, 0L, 0L, 0L, 0, 0, "sd", SHAPE_MOUSE}, 3468 {0, 0, 0, 0L, 0L, 0L, 0, 0, "vs", SHAPE_MOUSE}, 3469 {0, 0, 0, 0L, 0L, 0L, 0, 0, "vd", SHAPE_MOUSE}, 3470 {0, 0, 0, 0L, 0L, 0L, 0, 0, "m", SHAPE_MOUSE}, 3471 {0, 0, 0, 0L, 0L, 0L, 0, 0, "ml", SHAPE_MOUSE}, 3472 {0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR}, 3473 }; 3474 3475 #ifdef FEAT_MOUSESHAPE 3476 /* 3477 * Table with names for mouse shapes. Keep in sync with all the tables for 3478 * mch_set_mouse_shape()!. 3479 */ 3480 static char * mshape_names[] = 3481 { 3482 "arrow", /* default, must be the first one */ 3483 "blank", /* hidden */ 3484 "beam", 3485 "updown", 3486 "udsizing", 3487 "leftright", 3488 "lrsizing", 3489 "busy", 3490 "no", 3491 "crosshair", 3492 "hand1", 3493 "hand2", 3494 "pencil", 3495 "question", 3496 "rightup-arrow", 3497 "up-arrow", 3498 NULL 3499 }; 3500 #endif 3501 3502 /* 3503 * Parse the 'guicursor' option ("what" is SHAPE_CURSOR) or 'mouseshape' 3504 * ("what" is SHAPE_MOUSE). 3505 * Returns error message for an illegal option, NULL otherwise. 3506 */ 3507 char_u * 3508 parse_shape_opt(int what) 3509 { 3510 char_u *modep; 3511 char_u *colonp; 3512 char_u *commap; 3513 char_u *slashp; 3514 char_u *p, *endp; 3515 int idx = 0; /* init for GCC */ 3516 int all_idx; 3517 int len; 3518 int i; 3519 long n; 3520 int found_ve = FALSE; /* found "ve" flag */ 3521 int round; 3522 3523 /* 3524 * First round: check for errors; second round: do it for real. 3525 */ 3526 for (round = 1; round <= 2; ++round) 3527 { 3528 /* 3529 * Repeat for all comma separated parts. 3530 */ 3531 #ifdef FEAT_MOUSESHAPE 3532 if (what == SHAPE_MOUSE) 3533 modep = p_mouseshape; 3534 else 3535 #endif 3536 modep = p_guicursor; 3537 while (*modep != NUL) 3538 { 3539 colonp = vim_strchr(modep, ':'); 3540 commap = vim_strchr(modep, ','); 3541 3542 if (colonp == NULL || (commap != NULL && commap < colonp)) 3543 return (char_u *)N_("E545: Missing colon"); 3544 if (colonp == modep) 3545 return (char_u *)N_("E546: Illegal mode"); 3546 3547 /* 3548 * Repeat for all mode's before the colon. 3549 * For the 'a' mode, we loop to handle all the modes. 3550 */ 3551 all_idx = -1; 3552 while (modep < colonp || all_idx >= 0) 3553 { 3554 if (all_idx < 0) 3555 { 3556 /* Find the mode. */ 3557 if (modep[1] == '-' || modep[1] == ':') 3558 len = 1; 3559 else 3560 len = 2; 3561 if (len == 1 && TOLOWER_ASC(modep[0]) == 'a') 3562 all_idx = SHAPE_IDX_COUNT - 1; 3563 else 3564 { 3565 for (idx = 0; idx < SHAPE_IDX_COUNT; ++idx) 3566 if (STRNICMP(modep, shape_table[idx].name, len) 3567 == 0) 3568 break; 3569 if (idx == SHAPE_IDX_COUNT 3570 || (shape_table[idx].used_for & what) == 0) 3571 return (char_u *)N_("E546: Illegal mode"); 3572 if (len == 2 && modep[0] == 'v' && modep[1] == 'e') 3573 found_ve = TRUE; 3574 } 3575 modep += len + 1; 3576 } 3577 3578 if (all_idx >= 0) 3579 idx = all_idx--; 3580 else if (round == 2) 3581 { 3582 #ifdef FEAT_MOUSESHAPE 3583 if (what == SHAPE_MOUSE) 3584 { 3585 /* Set the default, for the missing parts */ 3586 shape_table[idx].mshape = 0; 3587 } 3588 else 3589 #endif 3590 { 3591 /* Set the defaults, for the missing parts */ 3592 shape_table[idx].shape = SHAPE_BLOCK; 3593 shape_table[idx].blinkwait = 700L; 3594 shape_table[idx].blinkon = 400L; 3595 shape_table[idx].blinkoff = 250L; 3596 } 3597 } 3598 3599 /* Parse the part after the colon */ 3600 for (p = colonp + 1; *p && *p != ','; ) 3601 { 3602 #ifdef FEAT_MOUSESHAPE 3603 if (what == SHAPE_MOUSE) 3604 { 3605 for (i = 0; ; ++i) 3606 { 3607 if (mshape_names[i] == NULL) 3608 { 3609 if (!VIM_ISDIGIT(*p)) 3610 return (char_u *)N_("E547: Illegal mouseshape"); 3611 if (round == 2) 3612 shape_table[idx].mshape = 3613 getdigits(&p) + MSHAPE_NUMBERED; 3614 else 3615 (void)getdigits(&p); 3616 break; 3617 } 3618 len = (int)STRLEN(mshape_names[i]); 3619 if (STRNICMP(p, mshape_names[i], len) == 0) 3620 { 3621 if (round == 2) 3622 shape_table[idx].mshape = i; 3623 p += len; 3624 break; 3625 } 3626 } 3627 } 3628 else /* if (what == SHAPE_MOUSE) */ 3629 #endif 3630 { 3631 /* 3632 * First handle the ones with a number argument. 3633 */ 3634 i = *p; 3635 len = 0; 3636 if (STRNICMP(p, "ver", 3) == 0) 3637 len = 3; 3638 else if (STRNICMP(p, "hor", 3) == 0) 3639 len = 3; 3640 else if (STRNICMP(p, "blinkwait", 9) == 0) 3641 len = 9; 3642 else if (STRNICMP(p, "blinkon", 7) == 0) 3643 len = 7; 3644 else if (STRNICMP(p, "blinkoff", 8) == 0) 3645 len = 8; 3646 if (len != 0) 3647 { 3648 p += len; 3649 if (!VIM_ISDIGIT(*p)) 3650 return (char_u *)N_("E548: digit expected"); 3651 n = getdigits(&p); 3652 if (len == 3) /* "ver" or "hor" */ 3653 { 3654 if (n == 0) 3655 return (char_u *)N_("E549: Illegal percentage"); 3656 if (round == 2) 3657 { 3658 if (TOLOWER_ASC(i) == 'v') 3659 shape_table[idx].shape = SHAPE_VER; 3660 else 3661 shape_table[idx].shape = SHAPE_HOR; 3662 shape_table[idx].percentage = n; 3663 } 3664 } 3665 else if (round == 2) 3666 { 3667 if (len == 9) 3668 shape_table[idx].blinkwait = n; 3669 else if (len == 7) 3670 shape_table[idx].blinkon = n; 3671 else 3672 shape_table[idx].blinkoff = n; 3673 } 3674 } 3675 else if (STRNICMP(p, "block", 5) == 0) 3676 { 3677 if (round == 2) 3678 shape_table[idx].shape = SHAPE_BLOCK; 3679 p += 5; 3680 } 3681 else /* must be a highlight group name then */ 3682 { 3683 endp = vim_strchr(p, '-'); 3684 if (commap == NULL) /* last part */ 3685 { 3686 if (endp == NULL) 3687 endp = p + STRLEN(p); /* find end of part */ 3688 } 3689 else if (endp > commap || endp == NULL) 3690 endp = commap; 3691 slashp = vim_strchr(p, '/'); 3692 if (slashp != NULL && slashp < endp) 3693 { 3694 /* "group/langmap_group" */ 3695 i = syn_check_group(p, (int)(slashp - p)); 3696 p = slashp + 1; 3697 } 3698 if (round == 2) 3699 { 3700 shape_table[idx].id = syn_check_group(p, 3701 (int)(endp - p)); 3702 shape_table[idx].id_lm = shape_table[idx].id; 3703 if (slashp != NULL && slashp < endp) 3704 shape_table[idx].id = i; 3705 } 3706 p = endp; 3707 } 3708 } /* if (what != SHAPE_MOUSE) */ 3709 3710 if (*p == '-') 3711 ++p; 3712 } 3713 } 3714 modep = p; 3715 if (*modep == ',') 3716 ++modep; 3717 } 3718 } 3719 3720 /* If the 's' flag is not given, use the 'v' cursor for 's' */ 3721 if (!found_ve) 3722 { 3723 #ifdef FEAT_MOUSESHAPE 3724 if (what == SHAPE_MOUSE) 3725 { 3726 shape_table[SHAPE_IDX_VE].mshape = shape_table[SHAPE_IDX_V].mshape; 3727 } 3728 else 3729 #endif 3730 { 3731 shape_table[SHAPE_IDX_VE].shape = shape_table[SHAPE_IDX_V].shape; 3732 shape_table[SHAPE_IDX_VE].percentage = 3733 shape_table[SHAPE_IDX_V].percentage; 3734 shape_table[SHAPE_IDX_VE].blinkwait = 3735 shape_table[SHAPE_IDX_V].blinkwait; 3736 shape_table[SHAPE_IDX_VE].blinkon = 3737 shape_table[SHAPE_IDX_V].blinkon; 3738 shape_table[SHAPE_IDX_VE].blinkoff = 3739 shape_table[SHAPE_IDX_V].blinkoff; 3740 shape_table[SHAPE_IDX_VE].id = shape_table[SHAPE_IDX_V].id; 3741 shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm; 3742 } 3743 } 3744 3745 return NULL; 3746 } 3747 3748 # if defined(MCH_CURSOR_SHAPE) || defined(FEAT_GUI) \ 3749 || defined(FEAT_MOUSESHAPE) || defined(PROTO) 3750 /* 3751 * Return the index into shape_table[] for the current mode. 3752 * When "mouse" is TRUE, consider indexes valid for the mouse pointer. 3753 */ 3754 int 3755 get_shape_idx(int mouse) 3756 { 3757 #ifdef FEAT_MOUSESHAPE 3758 if (mouse && (State == HITRETURN || State == ASKMORE)) 3759 { 3760 # ifdef FEAT_GUI 3761 int x, y; 3762 gui_mch_getmouse(&x, &y); 3763 if (Y_2_ROW(y) == Rows - 1) 3764 return SHAPE_IDX_MOREL; 3765 # endif 3766 return SHAPE_IDX_MORE; 3767 } 3768 if (mouse && drag_status_line) 3769 return SHAPE_IDX_SDRAG; 3770 if (mouse && drag_sep_line) 3771 return SHAPE_IDX_VDRAG; 3772 #endif 3773 if (!mouse && State == SHOWMATCH) 3774 return SHAPE_IDX_SM; 3775 #ifdef FEAT_VREPLACE 3776 if (State & VREPLACE_FLAG) 3777 return SHAPE_IDX_R; 3778 #endif 3779 if (State & REPLACE_FLAG) 3780 return SHAPE_IDX_R; 3781 if (State & INSERT) 3782 return SHAPE_IDX_I; 3783 if (State & CMDLINE) 3784 { 3785 if (cmdline_at_end()) 3786 return SHAPE_IDX_C; 3787 if (cmdline_overstrike()) 3788 return SHAPE_IDX_CR; 3789 return SHAPE_IDX_CI; 3790 } 3791 if (finish_op) 3792 return SHAPE_IDX_O; 3793 if (VIsual_active) 3794 { 3795 if (*p_sel == 'e') 3796 return SHAPE_IDX_VE; 3797 else 3798 return SHAPE_IDX_V; 3799 } 3800 return SHAPE_IDX_N; 3801 } 3802 #endif 3803 3804 # if defined(FEAT_MOUSESHAPE) || defined(PROTO) 3805 static int old_mouse_shape = 0; 3806 3807 /* 3808 * Set the mouse shape: 3809 * If "shape" is -1, use shape depending on the current mode, 3810 * depending on the current state. 3811 * If "shape" is -2, only update the shape when it's CLINE or STATUS (used 3812 * when the mouse moves off the status or command line). 3813 */ 3814 void 3815 update_mouseshape(int shape_idx) 3816 { 3817 int new_mouse_shape; 3818 3819 /* Only works in GUI mode. */ 3820 if (!gui.in_use || gui.starting) 3821 return; 3822 3823 /* Postpone the updating when more is to come. Speeds up executing of 3824 * mappings. */ 3825 if (shape_idx == -1 && char_avail()) 3826 { 3827 postponed_mouseshape = TRUE; 3828 return; 3829 } 3830 3831 /* When ignoring the mouse don't change shape on the statusline. */ 3832 if (*p_mouse == NUL 3833 && (shape_idx == SHAPE_IDX_CLINE 3834 || shape_idx == SHAPE_IDX_STATUS 3835 || shape_idx == SHAPE_IDX_VSEP)) 3836 shape_idx = -2; 3837 3838 if (shape_idx == -2 3839 && old_mouse_shape != shape_table[SHAPE_IDX_CLINE].mshape 3840 && old_mouse_shape != shape_table[SHAPE_IDX_STATUS].mshape 3841 && old_mouse_shape != shape_table[SHAPE_IDX_VSEP].mshape) 3842 return; 3843 if (shape_idx < 0) 3844 new_mouse_shape = shape_table[get_shape_idx(TRUE)].mshape; 3845 else 3846 new_mouse_shape = shape_table[shape_idx].mshape; 3847 if (new_mouse_shape != old_mouse_shape) 3848 { 3849 mch_set_mouse_shape(new_mouse_shape); 3850 old_mouse_shape = new_mouse_shape; 3851 } 3852 postponed_mouseshape = FALSE; 3853 } 3854 # endif 3855 3856 #endif /* CURSOR_SHAPE */ 3857 3858 3859 /* TODO: make some #ifdef for this */ 3860 /*--------[ file searching ]-------------------------------------------------*/ 3861 /* 3862 * File searching functions for 'path', 'tags' and 'cdpath' options. 3863 * External visible functions: 3864 * vim_findfile_init() creates/initialises the search context 3865 * vim_findfile_free_visited() free list of visited files/dirs of search 3866 * context 3867 * vim_findfile() find a file in the search context 3868 * vim_findfile_cleanup() cleanup/free search context created by 3869 * vim_findfile_init() 3870 * 3871 * All static functions and variables start with 'ff_' 3872 * 3873 * In general it works like this: 3874 * First you create yourself a search context by calling vim_findfile_init(). 3875 * It is possible to give a search context from a previous call to 3876 * vim_findfile_init(), so it can be reused. After this you call vim_findfile() 3877 * until you are satisfied with the result or it returns NULL. On every call it 3878 * returns the next file which matches the conditions given to 3879 * vim_findfile_init(). If it doesn't find a next file it returns NULL. 3880 * 3881 * It is possible to call vim_findfile_init() again to reinitialise your search 3882 * with some new parameters. Don't forget to pass your old search context to 3883 * it, so it can reuse it and especially reuse the list of already visited 3884 * directories. If you want to delete the list of already visited directories 3885 * simply call vim_findfile_free_visited(). 3886 * 3887 * When you are done call vim_findfile_cleanup() to free the search context. 3888 * 3889 * The function vim_findfile_init() has a long comment, which describes the 3890 * needed parameters. 3891 * 3892 * 3893 * 3894 * ATTENTION: 3895 * ========== 3896 * Also we use an allocated search context here, this functions are NOT 3897 * thread-safe!!!!! 3898 * 3899 * To minimize parameter passing (or because I'm to lazy), only the 3900 * external visible functions get a search context as a parameter. This is 3901 * then assigned to a static global, which is used throughout the local 3902 * functions. 3903 */ 3904 3905 /* 3906 * type for the directory search stack 3907 */ 3908 typedef struct ff_stack 3909 { 3910 struct ff_stack *ffs_prev; 3911 3912 /* the fix part (no wildcards) and the part containing the wildcards 3913 * of the search path 3914 */ 3915 char_u *ffs_fix_path; 3916 #ifdef FEAT_PATH_EXTRA 3917 char_u *ffs_wc_path; 3918 #endif 3919 3920 /* files/dirs found in the above directory, matched by the first wildcard 3921 * of wc_part 3922 */ 3923 char_u **ffs_filearray; 3924 int ffs_filearray_size; 3925 char_u ffs_filearray_cur; /* needed for partly handled dirs */ 3926 3927 /* to store status of partly handled directories 3928 * 0: we work on this directory for the first time 3929 * 1: this directory was partly searched in an earlier step 3930 */ 3931 int ffs_stage; 3932 3933 /* How deep are we in the directory tree? 3934 * Counts backward from value of level parameter to vim_findfile_init 3935 */ 3936 int ffs_level; 3937 3938 /* Did we already expand '**' to an empty string? */ 3939 int ffs_star_star_empty; 3940 } ff_stack_T; 3941 3942 /* 3943 * type for already visited directories or files. 3944 */ 3945 typedef struct ff_visited 3946 { 3947 struct ff_visited *ffv_next; 3948 3949 #ifdef FEAT_PATH_EXTRA 3950 /* Visited directories are different if the wildcard string are 3951 * different. So we have to save it. 3952 */ 3953 char_u *ffv_wc_path; 3954 #endif 3955 /* for unix use inode etc for comparison (needed because of links), else 3956 * use filename. 3957 */ 3958 #ifdef UNIX 3959 int ffv_dev_valid; /* ffv_dev and ffv_ino were set */ 3960 dev_t ffv_dev; /* device number */ 3961 ino_t ffv_ino; /* inode number */ 3962 #endif 3963 /* The memory for this struct is allocated according to the length of 3964 * ffv_fname. 3965 */ 3966 char_u ffv_fname[1]; /* actually longer */ 3967 } ff_visited_T; 3968 3969 /* 3970 * We might have to manage several visited lists during a search. 3971 * This is especially needed for the tags option. If tags is set to: 3972 * "./++/tags,./++/TAGS,++/tags" (replace + with *) 3973 * So we have to do 3 searches: 3974 * 1) search from the current files directory downward for the file "tags" 3975 * 2) search from the current files directory downward for the file "TAGS" 3976 * 3) search from Vims current directory downwards for the file "tags" 3977 * As you can see, the first and the third search are for the same file, so for 3978 * the third search we can use the visited list of the first search. For the 3979 * second search we must start from a empty visited list. 3980 * The struct ff_visited_list_hdr is used to manage a linked list of already 3981 * visited lists. 3982 */ 3983 typedef struct ff_visited_list_hdr 3984 { 3985 struct ff_visited_list_hdr *ffvl_next; 3986 3987 /* the filename the attached visited list is for */ 3988 char_u *ffvl_filename; 3989 3990 ff_visited_T *ffvl_visited_list; 3991 3992 } ff_visited_list_hdr_T; 3993 3994 3995 /* 3996 * '**' can be expanded to several directory levels. 3997 * Set the default maximum depth. 3998 */ 3999 #define FF_MAX_STAR_STAR_EXPAND ((char_u)30) 4000 4001 /* 4002 * The search context: 4003 * ffsc_stack_ptr: the stack for the dirs to search 4004 * ffsc_visited_list: the currently active visited list 4005 * ffsc_dir_visited_list: the currently active visited list for search dirs 4006 * ffsc_visited_lists_list: the list of all visited lists 4007 * ffsc_dir_visited_lists_list: the list of all visited lists for search dirs 4008 * ffsc_file_to_search: the file to search for 4009 * ffsc_start_dir: the starting directory, if search path was relative 4010 * ffsc_fix_path: the fix part of the given path (without wildcards) 4011 * Needed for upward search. 4012 * ffsc_wc_path: the part of the given path containing wildcards 4013 * ffsc_level: how many levels of dirs to search downwards 4014 * ffsc_stopdirs_v: array of stop directories for upward search 4015 * ffsc_find_what: FINDFILE_BOTH, FINDFILE_DIR or FINDFILE_FILE 4016 * ffsc_tagfile: searching for tags file, don't use 'suffixesadd' 4017 */ 4018 typedef struct ff_search_ctx_T 4019 { 4020 ff_stack_T *ffsc_stack_ptr; 4021 ff_visited_list_hdr_T *ffsc_visited_list; 4022 ff_visited_list_hdr_T *ffsc_dir_visited_list; 4023 ff_visited_list_hdr_T *ffsc_visited_lists_list; 4024 ff_visited_list_hdr_T *ffsc_dir_visited_lists_list; 4025 char_u *ffsc_file_to_search; 4026 char_u *ffsc_start_dir; 4027 char_u *ffsc_fix_path; 4028 #ifdef FEAT_PATH_EXTRA 4029 char_u *ffsc_wc_path; 4030 int ffsc_level; 4031 char_u **ffsc_stopdirs_v; 4032 #endif 4033 int ffsc_find_what; 4034 int ffsc_tagfile; 4035 } ff_search_ctx_T; 4036 4037 /* locally needed functions */ 4038 #ifdef FEAT_PATH_EXTRA 4039 static int ff_check_visited(ff_visited_T **, char_u *, char_u *); 4040 #else 4041 static int ff_check_visited(ff_visited_T **, char_u *); 4042 #endif 4043 static void vim_findfile_free_visited_list(ff_visited_list_hdr_T **list_headp); 4044 static void ff_free_visited_list(ff_visited_T *vl); 4045 static ff_visited_list_hdr_T* ff_get_visited_list(char_u *, ff_visited_list_hdr_T **list_headp); 4046 #ifdef FEAT_PATH_EXTRA 4047 static int ff_wc_equal(char_u *s1, char_u *s2); 4048 #endif 4049 4050 static void ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr); 4051 static ff_stack_T *ff_pop(ff_search_ctx_T *search_ctx); 4052 static void ff_clear(ff_search_ctx_T *search_ctx); 4053 static void ff_free_stack_element(ff_stack_T *stack_ptr); 4054 #ifdef FEAT_PATH_EXTRA 4055 static ff_stack_T *ff_create_stack_element(char_u *, char_u *, int, int); 4056 #else 4057 static ff_stack_T *ff_create_stack_element(char_u *, int, int); 4058 #endif 4059 #ifdef FEAT_PATH_EXTRA 4060 static int ff_path_in_stoplist(char_u *, int, char_u **); 4061 #endif 4062 4063 static char_u e_pathtoolong[] = N_("E854: path too long for completion"); 4064 4065 #if 0 4066 /* 4067 * if someone likes findfirst/findnext, here are the functions 4068 * NOT TESTED!! 4069 */ 4070 4071 static void *ff_fn_search_context = NULL; 4072 4073 char_u * 4074 vim_findfirst(char_u *path, char_u *filename, int level) 4075 { 4076 ff_fn_search_context = 4077 vim_findfile_init(path, filename, NULL, level, TRUE, FALSE, 4078 ff_fn_search_context, rel_fname); 4079 if (NULL == ff_fn_search_context) 4080 return NULL; 4081 else 4082 return vim_findnext() 4083 } 4084 4085 char_u * 4086 vim_findnext(void) 4087 { 4088 char_u *ret = vim_findfile(ff_fn_search_context); 4089 4090 if (NULL == ret) 4091 { 4092 vim_findfile_cleanup(ff_fn_search_context); 4093 ff_fn_search_context = NULL; 4094 } 4095 return ret; 4096 } 4097 #endif 4098 4099 /* 4100 * Initialization routine for vim_findfile(). 4101 * 4102 * Returns the newly allocated search context or NULL if an error occurred. 4103 * 4104 * Don't forget to clean up by calling vim_findfile_cleanup() if you are done 4105 * with the search context. 4106 * 4107 * Find the file 'filename' in the directory 'path'. 4108 * The parameter 'path' may contain wildcards. If so only search 'level' 4109 * directories deep. The parameter 'level' is the absolute maximum and is 4110 * not related to restricts given to the '**' wildcard. If 'level' is 100 4111 * and you use '**200' vim_findfile() will stop after 100 levels. 4112 * 4113 * 'filename' cannot contain wildcards! It is used as-is, no backslashes to 4114 * escape special characters. 4115 * 4116 * If 'stopdirs' is not NULL and nothing is found downward, the search is 4117 * restarted on the next higher directory level. This is repeated until the 4118 * start-directory of a search is contained in 'stopdirs'. 'stopdirs' has the 4119 * format ";*<dirname>*\(;<dirname>\)*;\=$". 4120 * 4121 * If the 'path' is relative, the starting dir for the search is either VIM's 4122 * current dir or if the path starts with "./" the current files dir. 4123 * If the 'path' is absolute, the starting dir is that part of the path before 4124 * the first wildcard. 4125 * 4126 * Upward search is only done on the starting dir. 4127 * 4128 * If 'free_visited' is TRUE the list of already visited files/directories is 4129 * cleared. Set this to FALSE if you just want to search from another 4130 * directory, but want to be sure that no directory from a previous search is 4131 * searched again. This is useful if you search for a file at different places. 4132 * The list of visited files/dirs can also be cleared with the function 4133 * vim_findfile_free_visited(). 4134 * 4135 * Set the parameter 'find_what' to FINDFILE_DIR if you want to search for 4136 * directories only, FINDFILE_FILE for files only, FINDFILE_BOTH for both. 4137 * 4138 * A search context returned by a previous call to vim_findfile_init() can be 4139 * passed in the parameter "search_ctx_arg". This context is reused and 4140 * reinitialized with the new parameters. The list of already visited 4141 * directories from this context is only deleted if the parameter 4142 * "free_visited" is true. Be aware that the passed "search_ctx_arg" is freed 4143 * if the reinitialization fails. 4144 * 4145 * If you don't have a search context from a previous call "search_ctx_arg" 4146 * must be NULL. 4147 * 4148 * This function silently ignores a few errors, vim_findfile() will have 4149 * limited functionality then. 4150 */ 4151 void * 4152 vim_findfile_init( 4153 char_u *path, 4154 char_u *filename, 4155 char_u *stopdirs UNUSED, 4156 int level, 4157 int free_visited, 4158 int find_what, 4159 void *search_ctx_arg, 4160 int tagfile, /* expanding names of tags files */ 4161 char_u *rel_fname) /* file name to use for "." */ 4162 { 4163 #ifdef FEAT_PATH_EXTRA 4164 char_u *wc_part; 4165 #endif 4166 ff_stack_T *sptr; 4167 ff_search_ctx_T *search_ctx; 4168 4169 /* If a search context is given by the caller, reuse it, else allocate a 4170 * new one. 4171 */ 4172 if (search_ctx_arg != NULL) 4173 search_ctx = search_ctx_arg; 4174 else 4175 { 4176 search_ctx = (ff_search_ctx_T*)alloc((unsigned)sizeof(ff_search_ctx_T)); 4177 if (search_ctx == NULL) 4178 goto error_return; 4179 vim_memset(search_ctx, 0, sizeof(ff_search_ctx_T)); 4180 } 4181 search_ctx->ffsc_find_what = find_what; 4182 search_ctx->ffsc_tagfile = tagfile; 4183 4184 /* clear the search context, but NOT the visited lists */ 4185 ff_clear(search_ctx); 4186 4187 /* clear visited list if wanted */ 4188 if (free_visited == TRUE) 4189 vim_findfile_free_visited(search_ctx); 4190 else 4191 { 4192 /* Reuse old visited lists. Get the visited list for the given 4193 * filename. If no list for the current filename exists, creates a new 4194 * one. */ 4195 search_ctx->ffsc_visited_list = ff_get_visited_list(filename, 4196 &search_ctx->ffsc_visited_lists_list); 4197 if (search_ctx->ffsc_visited_list == NULL) 4198 goto error_return; 4199 search_ctx->ffsc_dir_visited_list = ff_get_visited_list(filename, 4200 &search_ctx->ffsc_dir_visited_lists_list); 4201 if (search_ctx->ffsc_dir_visited_list == NULL) 4202 goto error_return; 4203 } 4204 4205 if (ff_expand_buffer == NULL) 4206 { 4207 ff_expand_buffer = (char_u*)alloc(MAXPATHL); 4208 if (ff_expand_buffer == NULL) 4209 goto error_return; 4210 } 4211 4212 /* Store information on starting dir now if path is relative. 4213 * If path is absolute, we do that later. */ 4214 if (path[0] == '.' 4215 && (vim_ispathsep(path[1]) || path[1] == NUL) 4216 && (!tagfile || vim_strchr(p_cpo, CPO_DOTTAG) == NULL) 4217 && rel_fname != NULL) 4218 { 4219 int len = (int)(gettail(rel_fname) - rel_fname); 4220 4221 if (!vim_isAbsName(rel_fname) && len + 1 < MAXPATHL) 4222 { 4223 /* Make the start dir an absolute path name. */ 4224 vim_strncpy(ff_expand_buffer, rel_fname, len); 4225 search_ctx->ffsc_start_dir = FullName_save(ff_expand_buffer, FALSE); 4226 } 4227 else 4228 search_ctx->ffsc_start_dir = vim_strnsave(rel_fname, len); 4229 if (search_ctx->ffsc_start_dir == NULL) 4230 goto error_return; 4231 if (*++path != NUL) 4232 ++path; 4233 } 4234 else if (*path == NUL || !vim_isAbsName(path)) 4235 { 4236 #ifdef BACKSLASH_IN_FILENAME 4237 /* "c:dir" needs "c:" to be expanded, otherwise use current dir */ 4238 if (*path != NUL && path[1] == ':') 4239 { 4240 char_u drive[3]; 4241 4242 drive[0] = path[0]; 4243 drive[1] = ':'; 4244 drive[2] = NUL; 4245 if (vim_FullName(drive, ff_expand_buffer, MAXPATHL, TRUE) == FAIL) 4246 goto error_return; 4247 path += 2; 4248 } 4249 else 4250 #endif 4251 if (mch_dirname(ff_expand_buffer, MAXPATHL) == FAIL) 4252 goto error_return; 4253 4254 search_ctx->ffsc_start_dir = vim_strsave(ff_expand_buffer); 4255 if (search_ctx->ffsc_start_dir == NULL) 4256 goto error_return; 4257 4258 #ifdef BACKSLASH_IN_FILENAME 4259 /* A path that starts with "/dir" is relative to the drive, not to the 4260 * directory (but not for "//machine/dir"). Only use the drive name. */ 4261 if ((*path == '/' || *path == '\\') 4262 && path[1] != path[0] 4263 && search_ctx->ffsc_start_dir[1] == ':') 4264 search_ctx->ffsc_start_dir[2] = NUL; 4265 #endif 4266 } 4267 4268 #ifdef FEAT_PATH_EXTRA 4269 /* 4270 * If stopdirs are given, split them into an array of pointers. 4271 * If this fails (mem allocation), there is no upward search at all or a 4272 * stop directory is not recognized -> continue silently. 4273 * If stopdirs just contains a ";" or is empty, 4274 * search_ctx->ffsc_stopdirs_v will only contain a NULL pointer. This 4275 * is handled as unlimited upward search. See function 4276 * ff_path_in_stoplist() for details. 4277 */ 4278 if (stopdirs != NULL) 4279 { 4280 char_u *walker = stopdirs; 4281 int dircount; 4282 4283 while (*walker == ';') 4284 walker++; 4285 4286 dircount = 1; 4287 search_ctx->ffsc_stopdirs_v = 4288 (char_u **)alloc((unsigned)sizeof(char_u *)); 4289 4290 if (search_ctx->ffsc_stopdirs_v != NULL) 4291 { 4292 do 4293 { 4294 char_u *helper; 4295 void *ptr; 4296 4297 helper = walker; 4298 ptr = vim_realloc(search_ctx->ffsc_stopdirs_v, 4299 (dircount + 1) * sizeof(char_u *)); 4300 if (ptr) 4301 search_ctx->ffsc_stopdirs_v = ptr; 4302 else 4303 /* ignore, keep what we have and continue */ 4304 break; 4305 walker = vim_strchr(walker, ';'); 4306 if (walker) 4307 { 4308 search_ctx->ffsc_stopdirs_v[dircount-1] = 4309 vim_strnsave(helper, (int)(walker - helper)); 4310 walker++; 4311 } 4312 else 4313 /* this might be "", which means ascent till top 4314 * of directory tree. 4315 */ 4316 search_ctx->ffsc_stopdirs_v[dircount-1] = 4317 vim_strsave(helper); 4318 4319 dircount++; 4320 4321 } while (walker != NULL); 4322 search_ctx->ffsc_stopdirs_v[dircount-1] = NULL; 4323 } 4324 } 4325 #endif 4326 4327 #ifdef FEAT_PATH_EXTRA 4328 search_ctx->ffsc_level = level; 4329 4330 /* split into: 4331 * -fix path 4332 * -wildcard_stuff (might be NULL) 4333 */ 4334 wc_part = vim_strchr(path, '*'); 4335 if (wc_part != NULL) 4336 { 4337 int llevel; 4338 int len; 4339 char *errpt; 4340 4341 /* save the fix part of the path */ 4342 search_ctx->ffsc_fix_path = vim_strnsave(path, (int)(wc_part - path)); 4343 4344 /* 4345 * copy wc_path and add restricts to the '**' wildcard. 4346 * The octet after a '**' is used as a (binary) counter. 4347 * So '**3' is transposed to '**^C' ('^C' is ASCII value 3) 4348 * or '**76' is transposed to '**N'( 'N' is ASCII value 76). 4349 * For EBCDIC you get different character values. 4350 * If no restrict is given after '**' the default is used. 4351 * Due to this technique the path looks awful if you print it as a 4352 * string. 4353 */ 4354 len = 0; 4355 while (*wc_part != NUL) 4356 { 4357 if (len + 5 >= MAXPATHL) 4358 { 4359 EMSG(_(e_pathtoolong)); 4360 break; 4361 } 4362 if (STRNCMP(wc_part, "**", 2) == 0) 4363 { 4364 ff_expand_buffer[len++] = *wc_part++; 4365 ff_expand_buffer[len++] = *wc_part++; 4366 4367 llevel = strtol((char *)wc_part, &errpt, 10); 4368 if ((char_u *)errpt != wc_part && llevel > 0 && llevel < 255) 4369 ff_expand_buffer[len++] = llevel; 4370 else if ((char_u *)errpt != wc_part && llevel == 0) 4371 /* restrict is 0 -> remove already added '**' */ 4372 len -= 2; 4373 else 4374 ff_expand_buffer[len++] = FF_MAX_STAR_STAR_EXPAND; 4375 wc_part = (char_u *)errpt; 4376 if (*wc_part != NUL && !vim_ispathsep(*wc_part)) 4377 { 4378 EMSG2(_("E343: Invalid path: '**[number]' must be at the end of the path or be followed by '%s'."), PATHSEPSTR); 4379 goto error_return; 4380 } 4381 } 4382 else 4383 ff_expand_buffer[len++] = *wc_part++; 4384 } 4385 ff_expand_buffer[len] = NUL; 4386 search_ctx->ffsc_wc_path = vim_strsave(ff_expand_buffer); 4387 4388 if (search_ctx->ffsc_wc_path == NULL) 4389 goto error_return; 4390 } 4391 else 4392 #endif 4393 search_ctx->ffsc_fix_path = vim_strsave(path); 4394 4395 if (search_ctx->ffsc_start_dir == NULL) 4396 { 4397 /* store the fix part as startdir. 4398 * This is needed if the parameter path is fully qualified. 4399 */ 4400 search_ctx->ffsc_start_dir = vim_strsave(search_ctx->ffsc_fix_path); 4401 if (search_ctx->ffsc_start_dir == NULL) 4402 goto error_return; 4403 search_ctx->ffsc_fix_path[0] = NUL; 4404 } 4405 4406 /* create an absolute path */ 4407 if (STRLEN(search_ctx->ffsc_start_dir) 4408 + STRLEN(search_ctx->ffsc_fix_path) + 3 >= MAXPATHL) 4409 { 4410 EMSG(_(e_pathtoolong)); 4411 goto error_return; 4412 } 4413 STRCPY(ff_expand_buffer, search_ctx->ffsc_start_dir); 4414 add_pathsep(ff_expand_buffer); 4415 { 4416 int eb_len = (int)STRLEN(ff_expand_buffer); 4417 char_u *buf = alloc(eb_len 4418 + (int)STRLEN(search_ctx->ffsc_fix_path) + 1); 4419 4420 STRCPY(buf, ff_expand_buffer); 4421 STRCPY(buf + eb_len, search_ctx->ffsc_fix_path); 4422 if (mch_isdir(buf)) 4423 { 4424 STRCAT(ff_expand_buffer, search_ctx->ffsc_fix_path); 4425 add_pathsep(ff_expand_buffer); 4426 } 4427 #ifdef FEAT_PATH_EXTRA 4428 else 4429 { 4430 char_u *p = gettail(search_ctx->ffsc_fix_path); 4431 char_u *wc_path = NULL; 4432 char_u *temp = NULL; 4433 int len = 0; 4434 4435 if (p > search_ctx->ffsc_fix_path) 4436 { 4437 len = (int)(p - search_ctx->ffsc_fix_path) - 1; 4438 STRNCAT(ff_expand_buffer, search_ctx->ffsc_fix_path, len); 4439 add_pathsep(ff_expand_buffer); 4440 } 4441 else 4442 len = (int)STRLEN(search_ctx->ffsc_fix_path); 4443 4444 if (search_ctx->ffsc_wc_path != NULL) 4445 { 4446 wc_path = vim_strsave(search_ctx->ffsc_wc_path); 4447 temp = alloc((int)(STRLEN(search_ctx->ffsc_wc_path) 4448 + STRLEN(search_ctx->ffsc_fix_path + len) 4449 + 1)); 4450 if (temp == NULL || wc_path == NULL) 4451 { 4452 vim_free(buf); 4453 vim_free(temp); 4454 vim_free(wc_path); 4455 goto error_return; 4456 } 4457 4458 STRCPY(temp, search_ctx->ffsc_fix_path + len); 4459 STRCAT(temp, search_ctx->ffsc_wc_path); 4460 vim_free(search_ctx->ffsc_wc_path); 4461 vim_free(wc_path); 4462 search_ctx->ffsc_wc_path = temp; 4463 } 4464 } 4465 #endif 4466 vim_free(buf); 4467 } 4468 4469 sptr = ff_create_stack_element(ff_expand_buffer, 4470 #ifdef FEAT_PATH_EXTRA 4471 search_ctx->ffsc_wc_path, 4472 #endif 4473 level, 0); 4474 4475 if (sptr == NULL) 4476 goto error_return; 4477 4478 ff_push(search_ctx, sptr); 4479 4480 search_ctx->ffsc_file_to_search = vim_strsave(filename); 4481 if (search_ctx->ffsc_file_to_search == NULL) 4482 goto error_return; 4483 4484 return search_ctx; 4485 4486 error_return: 4487 /* 4488 * We clear the search context now! 4489 * Even when the caller gave us a (perhaps valid) context we free it here, 4490 * as we might have already destroyed it. 4491 */ 4492 vim_findfile_cleanup(search_ctx); 4493 return NULL; 4494 } 4495 4496 #if defined(FEAT_PATH_EXTRA) || defined(PROTO) 4497 /* 4498 * Get the stopdir string. Check that ';' is not escaped. 4499 */ 4500 char_u * 4501 vim_findfile_stopdir(char_u *buf) 4502 { 4503 char_u *r_ptr = buf; 4504 4505 while (*r_ptr != NUL && *r_ptr != ';') 4506 { 4507 if (r_ptr[0] == '\\' && r_ptr[1] == ';') 4508 { 4509 /* Overwrite the escape char, 4510 * use STRLEN(r_ptr) to move the trailing '\0'. */ 4511 STRMOVE(r_ptr, r_ptr + 1); 4512 r_ptr++; 4513 } 4514 r_ptr++; 4515 } 4516 if (*r_ptr == ';') 4517 { 4518 *r_ptr = 0; 4519 r_ptr++; 4520 } 4521 else if (*r_ptr == NUL) 4522 r_ptr = NULL; 4523 return r_ptr; 4524 } 4525 #endif 4526 4527 /* 4528 * Clean up the given search context. Can handle a NULL pointer. 4529 */ 4530 void 4531 vim_findfile_cleanup(void *ctx) 4532 { 4533 if (ctx == NULL) 4534 return; 4535 4536 vim_findfile_free_visited(ctx); 4537 ff_clear(ctx); 4538 vim_free(ctx); 4539 } 4540 4541 /* 4542 * Find a file in a search context. 4543 * The search context was created with vim_findfile_init() above. 4544 * Return a pointer to an allocated file name or NULL if nothing found. 4545 * To get all matching files call this function until you get NULL. 4546 * 4547 * If the passed search_context is NULL, NULL is returned. 4548 * 4549 * The search algorithm is depth first. To change this replace the 4550 * stack with a list (don't forget to leave partly searched directories on the 4551 * top of the list). 4552 */ 4553 char_u * 4554 vim_findfile(void *search_ctx_arg) 4555 { 4556 char_u *file_path; 4557 #ifdef FEAT_PATH_EXTRA 4558 char_u *rest_of_wildcards; 4559 char_u *path_end = NULL; 4560 #endif 4561 ff_stack_T *stackp; 4562 #if defined(FEAT_SEARCHPATH) || defined(FEAT_PATH_EXTRA) 4563 int len; 4564 #endif 4565 int i; 4566 char_u *p; 4567 #ifdef FEAT_SEARCHPATH 4568 char_u *suf; 4569 #endif 4570 ff_search_ctx_T *search_ctx; 4571 4572 if (search_ctx_arg == NULL) 4573 return NULL; 4574 4575 search_ctx = (ff_search_ctx_T *)search_ctx_arg; 4576 4577 /* 4578 * filepath is used as buffer for various actions and as the storage to 4579 * return a found filename. 4580 */ 4581 if ((file_path = alloc((int)MAXPATHL)) == NULL) 4582 return NULL; 4583 4584 #ifdef FEAT_PATH_EXTRA 4585 /* store the end of the start dir -- needed for upward search */ 4586 if (search_ctx->ffsc_start_dir != NULL) 4587 path_end = &search_ctx->ffsc_start_dir[ 4588 STRLEN(search_ctx->ffsc_start_dir)]; 4589 #endif 4590 4591 #ifdef FEAT_PATH_EXTRA 4592 /* upward search loop */ 4593 for (;;) 4594 { 4595 #endif 4596 /* downward search loop */ 4597 for (;;) 4598 { 4599 /* check if user user wants to stop the search*/ 4600 ui_breakcheck(); 4601 if (got_int) 4602 break; 4603 4604 /* get directory to work on from stack */ 4605 stackp = ff_pop(search_ctx); 4606 if (stackp == NULL) 4607 break; 4608 4609 /* 4610 * TODO: decide if we leave this test in 4611 * 4612 * GOOD: don't search a directory(-tree) twice. 4613 * BAD: - check linked list for every new directory entered. 4614 * - check for double files also done below 4615 * 4616 * Here we check if we already searched this directory. 4617 * We already searched a directory if: 4618 * 1) The directory is the same. 4619 * 2) We would use the same wildcard string. 4620 * 4621 * Good if you have links on same directory via several ways 4622 * or you have selfreferences in directories (e.g. SuSE Linux 6.3: 4623 * /etc/rc.d/init.d is linked to /etc/rc.d -> endless loop) 4624 * 4625 * This check is only needed for directories we work on for the 4626 * first time (hence stackp->ff_filearray == NULL) 4627 */ 4628 if (stackp->ffs_filearray == NULL 4629 && ff_check_visited(&search_ctx->ffsc_dir_visited_list 4630 ->ffvl_visited_list, 4631 stackp->ffs_fix_path 4632 #ifdef FEAT_PATH_EXTRA 4633 , stackp->ffs_wc_path 4634 #endif 4635 ) == FAIL) 4636 { 4637 #ifdef FF_VERBOSE 4638 if (p_verbose >= 5) 4639 { 4640 verbose_enter_scroll(); 4641 smsg((char_u *)"Already Searched: %s (%s)", 4642 stackp->ffs_fix_path, stackp->ffs_wc_path); 4643 /* don't overwrite this either */ 4644 msg_puts((char_u *)"\n"); 4645 verbose_leave_scroll(); 4646 } 4647 #endif 4648 ff_free_stack_element(stackp); 4649 continue; 4650 } 4651 #ifdef FF_VERBOSE 4652 else if (p_verbose >= 5) 4653 { 4654 verbose_enter_scroll(); 4655 smsg((char_u *)"Searching: %s (%s)", 4656 stackp->ffs_fix_path, stackp->ffs_wc_path); 4657 /* don't overwrite this either */ 4658 msg_puts((char_u *)"\n"); 4659 verbose_leave_scroll(); 4660 } 4661 #endif 4662 4663 /* check depth */ 4664 if (stackp->ffs_level <= 0) 4665 { 4666 ff_free_stack_element(stackp); 4667 continue; 4668 } 4669 4670 file_path[0] = NUL; 4671 4672 /* 4673 * If no filearray till now expand wildcards 4674 * The function expand_wildcards() can handle an array of paths 4675 * and all possible expands are returned in one array. We use this 4676 * to handle the expansion of '**' into an empty string. 4677 */ 4678 if (stackp->ffs_filearray == NULL) 4679 { 4680 char_u *dirptrs[2]; 4681 4682 /* we use filepath to build the path expand_wildcards() should 4683 * expand. 4684 */ 4685 dirptrs[0] = file_path; 4686 dirptrs[1] = NULL; 4687 4688 /* if we have a start dir copy it in */ 4689 if (!vim_isAbsName(stackp->ffs_fix_path) 4690 && search_ctx->ffsc_start_dir) 4691 { 4692 if (STRLEN(search_ctx->ffsc_start_dir) + 1 < MAXPATHL) 4693 { 4694 STRCPY(file_path, search_ctx->ffsc_start_dir); 4695 add_pathsep(file_path); 4696 } 4697 else 4698 goto fail; 4699 } 4700 4701 /* append the fix part of the search path */ 4702 if (STRLEN(file_path) + STRLEN(stackp->ffs_fix_path) + 1 < MAXPATHL) 4703 { 4704 STRCAT(file_path, stackp->ffs_fix_path); 4705 add_pathsep(file_path); 4706 } 4707 else 4708 goto fail; 4709 4710 #ifdef FEAT_PATH_EXTRA 4711 rest_of_wildcards = stackp->ffs_wc_path; 4712 if (*rest_of_wildcards != NUL) 4713 { 4714 len = (int)STRLEN(file_path); 4715 if (STRNCMP(rest_of_wildcards, "**", 2) == 0) 4716 { 4717 /* pointer to the restrict byte 4718 * The restrict byte is not a character! 4719 */ 4720 p = rest_of_wildcards + 2; 4721 4722 if (*p > 0) 4723 { 4724 (*p)--; 4725 if (len + 1 < MAXPATHL) 4726 file_path[len++] = '*'; 4727 else 4728 goto fail; 4729 } 4730 4731 if (*p == 0) 4732 { 4733 /* remove '**<numb> from wildcards */ 4734 STRMOVE(rest_of_wildcards, rest_of_wildcards + 3); 4735 } 4736 else 4737 rest_of_wildcards += 3; 4738 4739 if (stackp->ffs_star_star_empty == 0) 4740 { 4741 /* if not done before, expand '**' to empty */ 4742 stackp->ffs_star_star_empty = 1; 4743 dirptrs[1] = stackp->ffs_fix_path; 4744 } 4745 } 4746 4747 /* 4748 * Here we copy until the next path separator or the end of 4749 * the path. If we stop at a path separator, there is 4750 * still something else left. This is handled below by 4751 * pushing every directory returned from expand_wildcards() 4752 * on the stack again for further search. 4753 */ 4754 while (*rest_of_wildcards 4755 && !vim_ispathsep(*rest_of_wildcards)) 4756 if (len + 1 < MAXPATHL) 4757 file_path[len++] = *rest_of_wildcards++; 4758 else 4759 goto fail; 4760 4761 file_path[len] = NUL; 4762 if (vim_ispathsep(*rest_of_wildcards)) 4763 rest_of_wildcards++; 4764 } 4765 #endif 4766 4767 /* 4768 * Expand wildcards like "*" and "$VAR". 4769 * If the path is a URL don't try this. 4770 */ 4771 if (path_with_url(dirptrs[0])) 4772 { 4773 stackp->ffs_filearray = (char_u **) 4774 alloc((unsigned)sizeof(char *)); 4775 if (stackp->ffs_filearray != NULL 4776 && (stackp->ffs_filearray[0] 4777 = vim_strsave(dirptrs[0])) != NULL) 4778 stackp->ffs_filearray_size = 1; 4779 else 4780 stackp->ffs_filearray_size = 0; 4781 } 4782 else 4783 /* Add EW_NOTWILD because the expanded path may contain 4784 * wildcard characters that are to be taken literally. 4785 * This is a bit of a hack. */ 4786 expand_wildcards((dirptrs[1] == NULL) ? 1 : 2, dirptrs, 4787 &stackp->ffs_filearray_size, 4788 &stackp->ffs_filearray, 4789 EW_DIR|EW_ADDSLASH|EW_SILENT|EW_NOTWILD); 4790 4791 stackp->ffs_filearray_cur = 0; 4792 stackp->ffs_stage = 0; 4793 } 4794 #ifdef FEAT_PATH_EXTRA 4795 else 4796 rest_of_wildcards = &stackp->ffs_wc_path[ 4797 STRLEN(stackp->ffs_wc_path)]; 4798 #endif 4799 4800 if (stackp->ffs_stage == 0) 4801 { 4802 /* this is the first time we work on this directory */ 4803 #ifdef FEAT_PATH_EXTRA 4804 if (*rest_of_wildcards == NUL) 4805 #endif 4806 { 4807 /* 4808 * We don't have further wildcards to expand, so we have to 4809 * check for the final file now. 4810 */ 4811 for (i = stackp->ffs_filearray_cur; 4812 i < stackp->ffs_filearray_size; ++i) 4813 { 4814 if (!path_with_url(stackp->ffs_filearray[i]) 4815 && !mch_isdir(stackp->ffs_filearray[i])) 4816 continue; /* not a directory */ 4817 4818 /* prepare the filename to be checked for existence 4819 * below */ 4820 if (STRLEN(stackp->ffs_filearray[i]) + 1 4821 + STRLEN(search_ctx->ffsc_file_to_search) < MAXPATHL) 4822 { 4823 STRCPY(file_path, stackp->ffs_filearray[i]); 4824 add_pathsep(file_path); 4825 STRCAT(file_path, search_ctx->ffsc_file_to_search); 4826 } 4827 else 4828 goto fail; 4829 4830 /* 4831 * Try without extra suffix and then with suffixes 4832 * from 'suffixesadd'. 4833 */ 4834 #ifdef FEAT_SEARCHPATH 4835 len = (int)STRLEN(file_path); 4836 if (search_ctx->ffsc_tagfile) 4837 suf = (char_u *)""; 4838 else 4839 suf = curbuf->b_p_sua; 4840 for (;;) 4841 #endif 4842 { 4843 /* if file exists and we didn't already find it */ 4844 if ((path_with_url(file_path) 4845 || (mch_getperm(file_path) >= 0 4846 && (search_ctx->ffsc_find_what 4847 == FINDFILE_BOTH 4848 || ((search_ctx->ffsc_find_what 4849 == FINDFILE_DIR) 4850 == mch_isdir(file_path))))) 4851 #ifndef FF_VERBOSE 4852 && (ff_check_visited( 4853 &search_ctx->ffsc_visited_list->ffvl_visited_list, 4854 file_path 4855 #ifdef FEAT_PATH_EXTRA 4856 , (char_u *)"" 4857 #endif 4858 ) == OK) 4859 #endif 4860 ) 4861 { 4862 #ifdef FF_VERBOSE 4863 if (ff_check_visited( 4864 &search_ctx->ffsc_visited_list->ffvl_visited_list, 4865 file_path 4866 #ifdef FEAT_PATH_EXTRA 4867 , (char_u *)"" 4868 #endif 4869 ) == FAIL) 4870 { 4871 if (p_verbose >= 5) 4872 { 4873 verbose_enter_scroll(); 4874 smsg((char_u *)"Already: %s", 4875 file_path); 4876 /* don't overwrite this either */ 4877 msg_puts((char_u *)"\n"); 4878 verbose_leave_scroll(); 4879 } 4880 continue; 4881 } 4882 #endif 4883 4884 /* push dir to examine rest of subdirs later */ 4885 stackp->ffs_filearray_cur = i + 1; 4886 ff_push(search_ctx, stackp); 4887 4888 if (!path_with_url(file_path)) 4889 simplify_filename(file_path); 4890 if (mch_dirname(ff_expand_buffer, MAXPATHL) 4891 == OK) 4892 { 4893 p = shorten_fname(file_path, 4894 ff_expand_buffer); 4895 if (p != NULL) 4896 STRMOVE(file_path, p); 4897 } 4898 #ifdef FF_VERBOSE 4899 if (p_verbose >= 5) 4900 { 4901 verbose_enter_scroll(); 4902 smsg((char_u *)"HIT: %s", file_path); 4903 /* don't overwrite this either */ 4904 msg_puts((char_u *)"\n"); 4905 verbose_leave_scroll(); 4906 } 4907 #endif 4908 return file_path; 4909 } 4910 4911 #ifdef FEAT_SEARCHPATH 4912 /* Not found or found already, try next suffix. */ 4913 if (*suf == NUL) 4914 break; 4915 copy_option_part(&suf, file_path + len, 4916 MAXPATHL - len, ","); 4917 #endif 4918 } 4919 } 4920 } 4921 #ifdef FEAT_PATH_EXTRA 4922 else 4923 { 4924 /* 4925 * still wildcards left, push the directories for further 4926 * search 4927 */ 4928 for (i = stackp->ffs_filearray_cur; 4929 i < stackp->ffs_filearray_size; ++i) 4930 { 4931 if (!mch_isdir(stackp->ffs_filearray[i])) 4932 continue; /* not a directory */ 4933 4934 ff_push(search_ctx, 4935 ff_create_stack_element( 4936 stackp->ffs_filearray[i], 4937 rest_of_wildcards, 4938 stackp->ffs_level - 1, 0)); 4939 } 4940 } 4941 #endif 4942 stackp->ffs_filearray_cur = 0; 4943 stackp->ffs_stage = 1; 4944 } 4945 4946 #ifdef FEAT_PATH_EXTRA 4947 /* 4948 * if wildcards contains '**' we have to descent till we reach the 4949 * leaves of the directory tree. 4950 */ 4951 if (STRNCMP(stackp->ffs_wc_path, "**", 2) == 0) 4952 { 4953 for (i = stackp->ffs_filearray_cur; 4954 i < stackp->ffs_filearray_size; ++i) 4955 { 4956 if (fnamecmp(stackp->ffs_filearray[i], 4957 stackp->ffs_fix_path) == 0) 4958 continue; /* don't repush same directory */ 4959 if (!mch_isdir(stackp->ffs_filearray[i])) 4960 continue; /* not a directory */ 4961 ff_push(search_ctx, 4962 ff_create_stack_element(stackp->ffs_filearray[i], 4963 stackp->ffs_wc_path, stackp->ffs_level - 1, 1)); 4964 } 4965 } 4966 #endif 4967 4968 /* we are done with the current directory */ 4969 ff_free_stack_element(stackp); 4970 4971 } 4972 4973 #ifdef FEAT_PATH_EXTRA 4974 /* If we reached this, we didn't find anything downwards. 4975 * Let's check if we should do an upward search. 4976 */ 4977 if (search_ctx->ffsc_start_dir 4978 && search_ctx->ffsc_stopdirs_v != NULL && !got_int) 4979 { 4980 ff_stack_T *sptr; 4981 4982 /* is the last starting directory in the stop list? */ 4983 if (ff_path_in_stoplist(search_ctx->ffsc_start_dir, 4984 (int)(path_end - search_ctx->ffsc_start_dir), 4985 search_ctx->ffsc_stopdirs_v) == TRUE) 4986 break; 4987 4988 /* cut of last dir */ 4989 while (path_end > search_ctx->ffsc_start_dir 4990 && vim_ispathsep(*path_end)) 4991 path_end--; 4992 while (path_end > search_ctx->ffsc_start_dir 4993 && !vim_ispathsep(path_end[-1])) 4994 path_end--; 4995 *path_end = 0; 4996 path_end--; 4997 4998 if (*search_ctx->ffsc_start_dir == 0) 4999 break; 5000 5001 if (STRLEN(search_ctx->ffsc_start_dir) + 1 5002 + STRLEN(search_ctx->ffsc_fix_path) < MAXPATHL) 5003 { 5004 STRCPY(file_path, search_ctx->ffsc_start_dir); 5005 add_pathsep(file_path); 5006 STRCAT(file_path, search_ctx->ffsc_fix_path); 5007 } 5008 else 5009 goto fail; 5010 5011 /* create a new stack entry */ 5012 sptr = ff_create_stack_element(file_path, 5013 search_ctx->ffsc_wc_path, search_ctx->ffsc_level, 0); 5014 if (sptr == NULL) 5015 break; 5016 ff_push(search_ctx, sptr); 5017 } 5018 else 5019 break; 5020 } 5021 #endif 5022 5023 fail: 5024 vim_free(file_path); 5025 return NULL; 5026 } 5027 5028 /* 5029 * Free the list of lists of visited files and directories 5030 * Can handle it if the passed search_context is NULL; 5031 */ 5032 void 5033 vim_findfile_free_visited(void *search_ctx_arg) 5034 { 5035 ff_search_ctx_T *search_ctx; 5036 5037 if (search_ctx_arg == NULL) 5038 return; 5039 5040 search_ctx = (ff_search_ctx_T *)search_ctx_arg; 5041 vim_findfile_free_visited_list(&search_ctx->ffsc_visited_lists_list); 5042 vim_findfile_free_visited_list(&search_ctx->ffsc_dir_visited_lists_list); 5043 } 5044 5045 static void 5046 vim_findfile_free_visited_list(ff_visited_list_hdr_T **list_headp) 5047 { 5048 ff_visited_list_hdr_T *vp; 5049 5050 while (*list_headp != NULL) 5051 { 5052 vp = (*list_headp)->ffvl_next; 5053 ff_free_visited_list((*list_headp)->ffvl_visited_list); 5054 5055 vim_free((*list_headp)->ffvl_filename); 5056 vim_free(*list_headp); 5057 *list_headp = vp; 5058 } 5059 *list_headp = NULL; 5060 } 5061 5062 static void 5063 ff_free_visited_list(ff_visited_T *vl) 5064 { 5065 ff_visited_T *vp; 5066 5067 while (vl != NULL) 5068 { 5069 vp = vl->ffv_next; 5070 #ifdef FEAT_PATH_EXTRA 5071 vim_free(vl->ffv_wc_path); 5072 #endif 5073 vim_free(vl); 5074 vl = vp; 5075 } 5076 vl = NULL; 5077 } 5078 5079 /* 5080 * Returns the already visited list for the given filename. If none is found it 5081 * allocates a new one. 5082 */ 5083 static ff_visited_list_hdr_T* 5084 ff_get_visited_list( 5085 char_u *filename, 5086 ff_visited_list_hdr_T **list_headp) 5087 { 5088 ff_visited_list_hdr_T *retptr = NULL; 5089 5090 /* check if a visited list for the given filename exists */ 5091 if (*list_headp != NULL) 5092 { 5093 retptr = *list_headp; 5094 while (retptr != NULL) 5095 { 5096 if (fnamecmp(filename, retptr->ffvl_filename) == 0) 5097 { 5098 #ifdef FF_VERBOSE 5099 if (p_verbose >= 5) 5100 { 5101 verbose_enter_scroll(); 5102 smsg((char_u *)"ff_get_visited_list: FOUND list for %s", 5103 filename); 5104 /* don't overwrite this either */ 5105 msg_puts((char_u *)"\n"); 5106 verbose_leave_scroll(); 5107 } 5108 #endif 5109 return retptr; 5110 } 5111 retptr = retptr->ffvl_next; 5112 } 5113 } 5114 5115 #ifdef FF_VERBOSE 5116 if (p_verbose >= 5) 5117 { 5118 verbose_enter_scroll(); 5119 smsg((char_u *)"ff_get_visited_list: new list for %s", filename); 5120 /* don't overwrite this either */ 5121 msg_puts((char_u *)"\n"); 5122 verbose_leave_scroll(); 5123 } 5124 #endif 5125 5126 /* 5127 * if we reach this we didn't find a list and we have to allocate new list 5128 */ 5129 retptr = (ff_visited_list_hdr_T*)alloc((unsigned)sizeof(*retptr)); 5130 if (retptr == NULL) 5131 return NULL; 5132 5133 retptr->ffvl_visited_list = NULL; 5134 retptr->ffvl_filename = vim_strsave(filename); 5135 if (retptr->ffvl_filename == NULL) 5136 { 5137 vim_free(retptr); 5138 return NULL; 5139 } 5140 retptr->ffvl_next = *list_headp; 5141 *list_headp = retptr; 5142 5143 return retptr; 5144 } 5145 5146 #ifdef FEAT_PATH_EXTRA 5147 /* 5148 * check if two wildcard paths are equal. Returns TRUE or FALSE. 5149 * They are equal if: 5150 * - both paths are NULL 5151 * - they have the same length 5152 * - char by char comparison is OK 5153 * - the only differences are in the counters behind a '**', so 5154 * '**\20' is equal to '**\24' 5155 */ 5156 static int 5157 ff_wc_equal(char_u *s1, char_u *s2) 5158 { 5159 int i, j; 5160 int c1 = NUL; 5161 int c2 = NUL; 5162 int prev1 = NUL; 5163 int prev2 = NUL; 5164 5165 if (s1 == s2) 5166 return TRUE; 5167 5168 if (s1 == NULL || s2 == NULL) 5169 return FALSE; 5170 5171 for (i = 0, j = 0; s1[i] != NUL && s2[j] != NUL;) 5172 { 5173 c1 = PTR2CHAR(s1 + i); 5174 c2 = PTR2CHAR(s2 + j); 5175 5176 if ((p_fic ? MB_TOLOWER(c1) != MB_TOLOWER(c2) : c1 != c2) 5177 && (prev1 != '*' || prev2 != '*')) 5178 return FALSE; 5179 prev2 = prev1; 5180 prev1 = c1; 5181 5182 i += MB_PTR2LEN(s1 + i); 5183 j += MB_PTR2LEN(s2 + j); 5184 } 5185 return s1[i] == s2[j]; 5186 } 5187 #endif 5188 5189 /* 5190 * maintains the list of already visited files and dirs 5191 * returns FAIL if the given file/dir is already in the list 5192 * returns OK if it is newly added 5193 * 5194 * TODO: What to do on memory allocation problems? 5195 * -> return TRUE - Better the file is found several times instead of 5196 * never. 5197 */ 5198 static int 5199 ff_check_visited( 5200 ff_visited_T **visited_list, 5201 char_u *fname 5202 #ifdef FEAT_PATH_EXTRA 5203 , char_u *wc_path 5204 #endif 5205 ) 5206 { 5207 ff_visited_T *vp; 5208 #ifdef UNIX 5209 stat_T st; 5210 int url = FALSE; 5211 #endif 5212 5213 /* For an URL we only compare the name, otherwise we compare the 5214 * device/inode (unix) or the full path name (not Unix). */ 5215 if (path_with_url(fname)) 5216 { 5217 vim_strncpy(ff_expand_buffer, fname, MAXPATHL - 1); 5218 #ifdef UNIX 5219 url = TRUE; 5220 #endif 5221 } 5222 else 5223 { 5224 ff_expand_buffer[0] = NUL; 5225 #ifdef UNIX 5226 if (mch_stat((char *)fname, &st) < 0) 5227 #else 5228 if (vim_FullName(fname, ff_expand_buffer, MAXPATHL, TRUE) == FAIL) 5229 #endif 5230 return FAIL; 5231 } 5232 5233 /* check against list of already visited files */ 5234 for (vp = *visited_list; vp != NULL; vp = vp->ffv_next) 5235 { 5236 if ( 5237 #ifdef UNIX 5238 !url ? (vp->ffv_dev_valid && vp->ffv_dev == st.st_dev 5239 && vp->ffv_ino == st.st_ino) 5240 : 5241 #endif 5242 fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0 5243 ) 5244 { 5245 #ifdef FEAT_PATH_EXTRA 5246 /* are the wildcard parts equal */ 5247 if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE) 5248 #endif 5249 /* already visited */ 5250 return FAIL; 5251 } 5252 } 5253 5254 /* 5255 * New file/dir. Add it to the list of visited files/dirs. 5256 */ 5257 vp = (ff_visited_T *)alloc((unsigned)(sizeof(ff_visited_T) 5258 + STRLEN(ff_expand_buffer))); 5259 5260 if (vp != NULL) 5261 { 5262 #ifdef UNIX 5263 if (!url) 5264 { 5265 vp->ffv_dev_valid = TRUE; 5266 vp->ffv_ino = st.st_ino; 5267 vp->ffv_dev = st.st_dev; 5268 vp->ffv_fname[0] = NUL; 5269 } 5270 else 5271 { 5272 vp->ffv_dev_valid = FALSE; 5273 #endif 5274 STRCPY(vp->ffv_fname, ff_expand_buffer); 5275 #ifdef UNIX 5276 } 5277 #endif 5278 #ifdef FEAT_PATH_EXTRA 5279 if (wc_path != NULL) 5280 vp->ffv_wc_path = vim_strsave(wc_path); 5281 else 5282 vp->ffv_wc_path = NULL; 5283 #endif 5284 5285 vp->ffv_next = *visited_list; 5286 *visited_list = vp; 5287 } 5288 5289 return OK; 5290 } 5291 5292 /* 5293 * create stack element from given path pieces 5294 */ 5295 static ff_stack_T * 5296 ff_create_stack_element( 5297 char_u *fix_part, 5298 #ifdef FEAT_PATH_EXTRA 5299 char_u *wc_part, 5300 #endif 5301 int level, 5302 int star_star_empty) 5303 { 5304 ff_stack_T *new; 5305 5306 new = (ff_stack_T *)alloc((unsigned)sizeof(ff_stack_T)); 5307 if (new == NULL) 5308 return NULL; 5309 5310 new->ffs_prev = NULL; 5311 new->ffs_filearray = NULL; 5312 new->ffs_filearray_size = 0; 5313 new->ffs_filearray_cur = 0; 5314 new->ffs_stage = 0; 5315 new->ffs_level = level; 5316 new->ffs_star_star_empty = star_star_empty; 5317 5318 /* the following saves NULL pointer checks in vim_findfile */ 5319 if (fix_part == NULL) 5320 fix_part = (char_u *)""; 5321 new->ffs_fix_path = vim_strsave(fix_part); 5322 5323 #ifdef FEAT_PATH_EXTRA 5324 if (wc_part == NULL) 5325 wc_part = (char_u *)""; 5326 new->ffs_wc_path = vim_strsave(wc_part); 5327 #endif 5328 5329 if (new->ffs_fix_path == NULL 5330 #ifdef FEAT_PATH_EXTRA 5331 || new->ffs_wc_path == NULL 5332 #endif 5333 ) 5334 { 5335 ff_free_stack_element(new); 5336 new = NULL; 5337 } 5338 5339 return new; 5340 } 5341 5342 /* 5343 * Push a dir on the directory stack. 5344 */ 5345 static void 5346 ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr) 5347 { 5348 /* check for NULL pointer, not to return an error to the user, but 5349 * to prevent a crash */ 5350 if (stack_ptr != NULL) 5351 { 5352 stack_ptr->ffs_prev = search_ctx->ffsc_stack_ptr; 5353 search_ctx->ffsc_stack_ptr = stack_ptr; 5354 } 5355 } 5356 5357 /* 5358 * Pop a dir from the directory stack. 5359 * Returns NULL if stack is empty. 5360 */ 5361 static ff_stack_T * 5362 ff_pop(ff_search_ctx_T *search_ctx) 5363 { 5364 ff_stack_T *sptr; 5365 5366 sptr = search_ctx->ffsc_stack_ptr; 5367 if (search_ctx->ffsc_stack_ptr != NULL) 5368 search_ctx->ffsc_stack_ptr = search_ctx->ffsc_stack_ptr->ffs_prev; 5369 5370 return sptr; 5371 } 5372 5373 /* 5374 * free the given stack element 5375 */ 5376 static void 5377 ff_free_stack_element(ff_stack_T *stack_ptr) 5378 { 5379 /* vim_free handles possible NULL pointers */ 5380 vim_free(stack_ptr->ffs_fix_path); 5381 #ifdef FEAT_PATH_EXTRA 5382 vim_free(stack_ptr->ffs_wc_path); 5383 #endif 5384 5385 if (stack_ptr->ffs_filearray != NULL) 5386 FreeWild(stack_ptr->ffs_filearray_size, stack_ptr->ffs_filearray); 5387 5388 vim_free(stack_ptr); 5389 } 5390 5391 /* 5392 * Clear the search context, but NOT the visited list. 5393 */ 5394 static void 5395 ff_clear(ff_search_ctx_T *search_ctx) 5396 { 5397 ff_stack_T *sptr; 5398 5399 /* clear up stack */ 5400 while ((sptr = ff_pop(search_ctx)) != NULL) 5401 ff_free_stack_element(sptr); 5402 5403 vim_free(search_ctx->ffsc_file_to_search); 5404 vim_free(search_ctx->ffsc_start_dir); 5405 vim_free(search_ctx->ffsc_fix_path); 5406 #ifdef FEAT_PATH_EXTRA 5407 vim_free(search_ctx->ffsc_wc_path); 5408 #endif 5409 5410 #ifdef FEAT_PATH_EXTRA 5411 if (search_ctx->ffsc_stopdirs_v != NULL) 5412 { 5413 int i = 0; 5414 5415 while (search_ctx->ffsc_stopdirs_v[i] != NULL) 5416 { 5417 vim_free(search_ctx->ffsc_stopdirs_v[i]); 5418 i++; 5419 } 5420 vim_free(search_ctx->ffsc_stopdirs_v); 5421 } 5422 search_ctx->ffsc_stopdirs_v = NULL; 5423 #endif 5424 5425 /* reset everything */ 5426 search_ctx->ffsc_file_to_search = NULL; 5427 search_ctx->ffsc_start_dir = NULL; 5428 search_ctx->ffsc_fix_path = NULL; 5429 #ifdef FEAT_PATH_EXTRA 5430 search_ctx->ffsc_wc_path = NULL; 5431 search_ctx->ffsc_level = 0; 5432 #endif 5433 } 5434 5435 #ifdef FEAT_PATH_EXTRA 5436 /* 5437 * check if the given path is in the stopdirs 5438 * returns TRUE if yes else FALSE 5439 */ 5440 static int 5441 ff_path_in_stoplist(char_u *path, int path_len, char_u **stopdirs_v) 5442 { 5443 int i = 0; 5444 5445 /* eat up trailing path separators, except the first */ 5446 while (path_len > 1 && vim_ispathsep(path[path_len - 1])) 5447 path_len--; 5448 5449 /* if no path consider it as match */ 5450 if (path_len == 0) 5451 return TRUE; 5452 5453 for (i = 0; stopdirs_v[i] != NULL; i++) 5454 { 5455 if ((int)STRLEN(stopdirs_v[i]) > path_len) 5456 { 5457 /* match for parent directory. So '/home' also matches 5458 * '/home/rks'. Check for PATHSEP in stopdirs_v[i], else 5459 * '/home/r' would also match '/home/rks' 5460 */ 5461 if (fnamencmp(stopdirs_v[i], path, path_len) == 0 5462 && vim_ispathsep(stopdirs_v[i][path_len])) 5463 return TRUE; 5464 } 5465 else 5466 { 5467 if (fnamecmp(stopdirs_v[i], path) == 0) 5468 return TRUE; 5469 } 5470 } 5471 return FALSE; 5472 } 5473 #endif 5474 5475 #if defined(FEAT_SEARCHPATH) || defined(PROTO) 5476 /* 5477 * Find the file name "ptr[len]" in the path. Also finds directory names. 5478 * 5479 * On the first call set the parameter 'first' to TRUE to initialize 5480 * the search. For repeating calls to FALSE. 5481 * 5482 * Repeating calls will return other files called 'ptr[len]' from the path. 5483 * 5484 * Only on the first call 'ptr' and 'len' are used. For repeating calls they 5485 * don't need valid values. 5486 * 5487 * If nothing found on the first call the option FNAME_MESS will issue the 5488 * message: 5489 * 'Can't find file "<file>" in path' 5490 * On repeating calls: 5491 * 'No more file "<file>" found in path' 5492 * 5493 * options: 5494 * FNAME_MESS give error message when not found 5495 * 5496 * Uses NameBuff[]! 5497 * 5498 * Returns an allocated string for the file name. NULL for error. 5499 * 5500 */ 5501 char_u * 5502 find_file_in_path( 5503 char_u *ptr, /* file name */ 5504 int len, /* length of file name */ 5505 int options, 5506 int first, /* use count'th matching file name */ 5507 char_u *rel_fname) /* file name searching relative to */ 5508 { 5509 return find_file_in_path_option(ptr, len, options, first, 5510 *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path, 5511 FINDFILE_BOTH, rel_fname, curbuf->b_p_sua); 5512 } 5513 5514 static char_u *ff_file_to_find = NULL; 5515 static void *fdip_search_ctx = NULL; 5516 5517 #if defined(EXITFREE) 5518 static void 5519 free_findfile(void) 5520 { 5521 vim_free(ff_file_to_find); 5522 vim_findfile_cleanup(fdip_search_ctx); 5523 } 5524 #endif 5525 5526 /* 5527 * Find the directory name "ptr[len]" in the path. 5528 * 5529 * options: 5530 * FNAME_MESS give error message when not found 5531 * FNAME_UNESC unescape backslashes. 5532 * 5533 * Uses NameBuff[]! 5534 * 5535 * Returns an allocated string for the file name. NULL for error. 5536 */ 5537 char_u * 5538 find_directory_in_path( 5539 char_u *ptr, /* file name */ 5540 int len, /* length of file name */ 5541 int options, 5542 char_u *rel_fname) /* file name searching relative to */ 5543 { 5544 return find_file_in_path_option(ptr, len, options, TRUE, p_cdpath, 5545 FINDFILE_DIR, rel_fname, (char_u *)""); 5546 } 5547 5548 char_u * 5549 find_file_in_path_option( 5550 char_u *ptr, /* file name */ 5551 int len, /* length of file name */ 5552 int options, 5553 int first, /* use count'th matching file name */ 5554 char_u *path_option, /* p_path or p_cdpath */ 5555 int find_what, /* FINDFILE_FILE, _DIR or _BOTH */ 5556 char_u *rel_fname, /* file name we are looking relative to. */ 5557 char_u *suffixes) /* list of suffixes, 'suffixesadd' option */ 5558 { 5559 static char_u *dir; 5560 static int did_findfile_init = FALSE; 5561 char_u save_char; 5562 char_u *file_name = NULL; 5563 char_u *buf = NULL; 5564 int rel_to_curdir; 5565 #ifdef AMIGA 5566 struct Process *proc = (struct Process *)FindTask(0L); 5567 APTR save_winptr = proc->pr_WindowPtr; 5568 5569 /* Avoid a requester here for a volume that doesn't exist. */ 5570 proc->pr_WindowPtr = (APTR)-1L; 5571 #endif 5572 5573 if (first == TRUE) 5574 { 5575 /* copy file name into NameBuff, expanding environment variables */ 5576 save_char = ptr[len]; 5577 ptr[len] = NUL; 5578 expand_env_esc(ptr, NameBuff, MAXPATHL, FALSE, TRUE, NULL); 5579 ptr[len] = save_char; 5580 5581 vim_free(ff_file_to_find); 5582 ff_file_to_find = vim_strsave(NameBuff); 5583 if (ff_file_to_find == NULL) /* out of memory */ 5584 { 5585 file_name = NULL; 5586 goto theend; 5587 } 5588 if (options & FNAME_UNESC) 5589 { 5590 /* Change all "\ " to " ". */ 5591 for (ptr = ff_file_to_find; *ptr != NUL; ++ptr) 5592 if (ptr[0] == '\\' && ptr[1] == ' ') 5593 mch_memmove(ptr, ptr + 1, STRLEN(ptr)); 5594 } 5595 } 5596 5597 rel_to_curdir = (ff_file_to_find[0] == '.' 5598 && (ff_file_to_find[1] == NUL 5599 || vim_ispathsep(ff_file_to_find[1]) 5600 || (ff_file_to_find[1] == '.' 5601 && (ff_file_to_find[2] == NUL 5602 || vim_ispathsep(ff_file_to_find[2]))))); 5603 if (vim_isAbsName(ff_file_to_find) 5604 /* "..", "../path", "." and "./path": don't use the path_option */ 5605 || rel_to_curdir 5606 #if defined(MSWIN) 5607 /* handle "\tmp" as absolute path */ 5608 || vim_ispathsep(ff_file_to_find[0]) 5609 /* handle "c:name" as absolute path */ 5610 || (ff_file_to_find[0] != NUL && ff_file_to_find[1] == ':') 5611 #endif 5612 #ifdef AMIGA 5613 /* handle ":tmp" as absolute path */ 5614 || ff_file_to_find[0] == ':' 5615 #endif 5616 ) 5617 { 5618 /* 5619 * Absolute path, no need to use "path_option". 5620 * If this is not a first call, return NULL. We already returned a 5621 * filename on the first call. 5622 */ 5623 if (first == TRUE) 5624 { 5625 int l; 5626 int run; 5627 5628 if (path_with_url(ff_file_to_find)) 5629 { 5630 file_name = vim_strsave(ff_file_to_find); 5631 goto theend; 5632 } 5633 5634 /* When FNAME_REL flag given first use the directory of the file. 5635 * Otherwise or when this fails use the current directory. */ 5636 for (run = 1; run <= 2; ++run) 5637 { 5638 l = (int)STRLEN(ff_file_to_find); 5639 if (run == 1 5640 && rel_to_curdir 5641 && (options & FNAME_REL) 5642 && rel_fname != NULL 5643 && STRLEN(rel_fname) + l < MAXPATHL) 5644 { 5645 STRCPY(NameBuff, rel_fname); 5646 STRCPY(gettail(NameBuff), ff_file_to_find); 5647 l = (int)STRLEN(NameBuff); 5648 } 5649 else 5650 { 5651 STRCPY(NameBuff, ff_file_to_find); 5652 run = 2; 5653 } 5654 5655 /* When the file doesn't exist, try adding parts of 5656 * 'suffixesadd'. */ 5657 buf = suffixes; 5658 for (;;) 5659 { 5660 if (mch_getperm(NameBuff) >= 0 5661 && (find_what == FINDFILE_BOTH 5662 || ((find_what == FINDFILE_DIR) 5663 == mch_isdir(NameBuff)))) 5664 { 5665 file_name = vim_strsave(NameBuff); 5666 goto theend; 5667 } 5668 if (*buf == NUL) 5669 break; 5670 copy_option_part(&buf, NameBuff + l, MAXPATHL - l, ","); 5671 } 5672 } 5673 } 5674 } 5675 else 5676 { 5677 /* 5678 * Loop over all paths in the 'path' or 'cdpath' option. 5679 * When "first" is set, first setup to the start of the option. 5680 * Otherwise continue to find the next match. 5681 */ 5682 if (first == TRUE) 5683 { 5684 /* vim_findfile_free_visited can handle a possible NULL pointer */ 5685 vim_findfile_free_visited(fdip_search_ctx); 5686 dir = path_option; 5687 did_findfile_init = FALSE; 5688 } 5689 5690 for (;;) 5691 { 5692 if (did_findfile_init) 5693 { 5694 file_name = vim_findfile(fdip_search_ctx); 5695 if (file_name != NULL) 5696 break; 5697 5698 did_findfile_init = FALSE; 5699 } 5700 else 5701 { 5702 char_u *r_ptr; 5703 5704 if (dir == NULL || *dir == NUL) 5705 { 5706 /* We searched all paths of the option, now we can 5707 * free the search context. */ 5708 vim_findfile_cleanup(fdip_search_ctx); 5709 fdip_search_ctx = NULL; 5710 break; 5711 } 5712 5713 if ((buf = alloc((int)(MAXPATHL))) == NULL) 5714 break; 5715 5716 /* copy next path */ 5717 buf[0] = 0; 5718 copy_option_part(&dir, buf, MAXPATHL, " ,"); 5719 5720 #ifdef FEAT_PATH_EXTRA 5721 /* get the stopdir string */ 5722 r_ptr = vim_findfile_stopdir(buf); 5723 #else 5724 r_ptr = NULL; 5725 #endif 5726 fdip_search_ctx = vim_findfile_init(buf, ff_file_to_find, 5727 r_ptr, 100, FALSE, find_what, 5728 fdip_search_ctx, FALSE, rel_fname); 5729 if (fdip_search_ctx != NULL) 5730 did_findfile_init = TRUE; 5731 vim_free(buf); 5732 } 5733 } 5734 } 5735 if (file_name == NULL && (options & FNAME_MESS)) 5736 { 5737 if (first == TRUE) 5738 { 5739 if (find_what == FINDFILE_DIR) 5740 EMSG2(_("E344: Can't find directory \"%s\" in cdpath"), 5741 ff_file_to_find); 5742 else 5743 EMSG2(_("E345: Can't find file \"%s\" in path"), 5744 ff_file_to_find); 5745 } 5746 else 5747 { 5748 if (find_what == FINDFILE_DIR) 5749 EMSG2(_("E346: No more directory \"%s\" found in cdpath"), 5750 ff_file_to_find); 5751 else 5752 EMSG2(_("E347: No more file \"%s\" found in path"), 5753 ff_file_to_find); 5754 } 5755 } 5756 5757 theend: 5758 #ifdef AMIGA 5759 proc->pr_WindowPtr = save_winptr; 5760 #endif 5761 return file_name; 5762 } 5763 5764 #endif /* FEAT_SEARCHPATH */ 5765 5766 /* 5767 * Change directory to "new_dir". If FEAT_SEARCHPATH is defined, search 5768 * 'cdpath' for relative directory names, otherwise just mch_chdir(). 5769 */ 5770 int 5771 vim_chdir(char_u *new_dir) 5772 { 5773 #ifndef FEAT_SEARCHPATH 5774 return mch_chdir((char *)new_dir); 5775 #else 5776 char_u *dir_name; 5777 int r; 5778 5779 dir_name = find_directory_in_path(new_dir, (int)STRLEN(new_dir), 5780 FNAME_MESS, curbuf->b_ffname); 5781 if (dir_name == NULL) 5782 return -1; 5783 r = mch_chdir((char *)dir_name); 5784 vim_free(dir_name); 5785 return r; 5786 #endif 5787 } 5788 5789 /* 5790 * Get user name from machine-specific function. 5791 * Returns the user name in "buf[len]". 5792 * Some systems are quite slow in obtaining the user name (Windows NT), thus 5793 * cache the result. 5794 * Returns OK or FAIL. 5795 */ 5796 int 5797 get_user_name(char_u *buf, int len) 5798 { 5799 if (username == NULL) 5800 { 5801 if (mch_get_user_name(buf, len) == FAIL) 5802 return FAIL; 5803 username = vim_strsave(buf); 5804 } 5805 else 5806 vim_strncpy(buf, username, len - 1); 5807 return OK; 5808 } 5809 5810 #ifndef HAVE_QSORT 5811 /* 5812 * Our own qsort(), for systems that don't have it. 5813 * It's simple and slow. From the K&R C book. 5814 */ 5815 void 5816 qsort( 5817 void *base, 5818 size_t elm_count, 5819 size_t elm_size, 5820 int (*cmp)(const void *, const void *)) 5821 { 5822 char_u *buf; 5823 char_u *p1; 5824 char_u *p2; 5825 int i, j; 5826 int gap; 5827 5828 buf = alloc((unsigned)elm_size); 5829 if (buf == NULL) 5830 return; 5831 5832 for (gap = elm_count / 2; gap > 0; gap /= 2) 5833 for (i = gap; i < elm_count; ++i) 5834 for (j = i - gap; j >= 0; j -= gap) 5835 { 5836 /* Compare the elements. */ 5837 p1 = (char_u *)base + j * elm_size; 5838 p2 = (char_u *)base + (j + gap) * elm_size; 5839 if ((*cmp)((void *)p1, (void *)p2) <= 0) 5840 break; 5841 /* Exchange the elements. */ 5842 mch_memmove(buf, p1, elm_size); 5843 mch_memmove(p1, p2, elm_size); 5844 mch_memmove(p2, buf, elm_size); 5845 } 5846 5847 vim_free(buf); 5848 } 5849 #endif 5850 5851 /* 5852 * Sort an array of strings. 5853 */ 5854 static int 5855 #ifdef __BORLANDC__ 5856 _RTLENTRYF 5857 #endif 5858 sort_compare(const void *s1, const void *s2); 5859 5860 static int 5861 #ifdef __BORLANDC__ 5862 _RTLENTRYF 5863 #endif 5864 sort_compare(const void *s1, const void *s2) 5865 { 5866 return STRCMP(*(char **)s1, *(char **)s2); 5867 } 5868 5869 void 5870 sort_strings( 5871 char_u **files, 5872 int count) 5873 { 5874 qsort((void *)files, (size_t)count, sizeof(char_u *), sort_compare); 5875 } 5876 5877 #if !defined(NO_EXPANDPATH) || defined(PROTO) 5878 /* 5879 * Compare path "p[]" to "q[]". 5880 * If "maxlen" >= 0 compare "p[maxlen]" to "q[maxlen]" 5881 * Return value like strcmp(p, q), but consider path separators. 5882 */ 5883 int 5884 pathcmp(const char *p, const char *q, int maxlen) 5885 { 5886 int i, j; 5887 int c1, c2; 5888 const char *s = NULL; 5889 5890 for (i = 0, j = 0; maxlen < 0 || (i < maxlen && j < maxlen);) 5891 { 5892 c1 = PTR2CHAR((char_u *)p + i); 5893 c2 = PTR2CHAR((char_u *)q + j); 5894 5895 /* End of "p": check if "q" also ends or just has a slash. */ 5896 if (c1 == NUL) 5897 { 5898 if (c2 == NUL) /* full match */ 5899 return 0; 5900 s = q; 5901 i = j; 5902 break; 5903 } 5904 5905 /* End of "q": check if "p" just has a slash. */ 5906 if (c2 == NUL) 5907 { 5908 s = p; 5909 break; 5910 } 5911 5912 if ((p_fic ? MB_TOUPPER(c1) != MB_TOUPPER(c2) : c1 != c2) 5913 #ifdef BACKSLASH_IN_FILENAME 5914 /* consider '/' and '\\' to be equal */ 5915 && !((c1 == '/' && c2 == '\\') 5916 || (c1 == '\\' && c2 == '/')) 5917 #endif 5918 ) 5919 { 5920 if (vim_ispathsep(c1)) 5921 return -1; 5922 if (vim_ispathsep(c2)) 5923 return 1; 5924 return p_fic ? MB_TOUPPER(c1) - MB_TOUPPER(c2) 5925 : c1 - c2; /* no match */ 5926 } 5927 5928 i += MB_PTR2LEN((char_u *)p + i); 5929 j += MB_PTR2LEN((char_u *)q + j); 5930 } 5931 if (s == NULL) /* "i" or "j" ran into "maxlen" */ 5932 return 0; 5933 5934 c1 = PTR2CHAR((char_u *)s + i); 5935 c2 = PTR2CHAR((char_u *)s + i + MB_PTR2LEN((char_u *)s + i)); 5936 /* ignore a trailing slash, but not "//" or ":/" */ 5937 if (c2 == NUL 5938 && i > 0 5939 && !after_pathsep((char_u *)s, (char_u *)s + i) 5940 #ifdef BACKSLASH_IN_FILENAME 5941 && (c1 == '/' || c1 == '\\') 5942 #else 5943 && c1 == '/' 5944 #endif 5945 ) 5946 return 0; /* match with trailing slash */ 5947 if (s == q) 5948 return -1; /* no match */ 5949 return 1; 5950 } 5951 #endif 5952 5953 /* 5954 * The putenv() implementation below comes from the "screen" program. 5955 * Included with permission from Juergen Weigert. 5956 * See pty.c for the copyright notice. 5957 */ 5958 5959 /* 5960 * putenv -- put value into environment 5961 * 5962 * Usage: i = putenv (string) 5963 * int i; 5964 * char *string; 5965 * 5966 * where string is of the form <name>=<value>. 5967 * Putenv returns 0 normally, -1 on error (not enough core for malloc). 5968 * 5969 * Putenv may need to add a new name into the environment, or to 5970 * associate a value longer than the current value with a particular 5971 * name. So, to make life simpler, putenv() copies your entire 5972 * environment into the heap (i.e. malloc()) from the stack 5973 * (i.e. where it resides when your process is initiated) the first 5974 * time you call it. 5975 * 5976 * (history removed, not very interesting. See the "screen" sources.) 5977 */ 5978 5979 #if !defined(HAVE_SETENV) && !defined(HAVE_PUTENV) 5980 5981 #define EXTRASIZE 5 /* increment to add to env. size */ 5982 5983 static int envsize = -1; /* current size of environment */ 5984 extern char **environ; /* the global which is your env. */ 5985 5986 static int findenv(char *name); /* look for a name in the env. */ 5987 static int newenv(void); /* copy env. from stack to heap */ 5988 static int moreenv(void); /* incr. size of env. */ 5989 5990 int 5991 putenv(const char *string) 5992 { 5993 int i; 5994 char *p; 5995 5996 if (envsize < 0) 5997 { /* first time putenv called */ 5998 if (newenv() < 0) /* copy env. to heap */ 5999 return -1; 6000 } 6001 6002 i = findenv((char *)string); /* look for name in environment */ 6003 6004 if (i < 0) 6005 { /* name must be added */ 6006 for (i = 0; environ[i]; i++); 6007 if (i >= (envsize - 1)) 6008 { /* need new slot */ 6009 if (moreenv() < 0) 6010 return -1; 6011 } 6012 p = (char *)alloc((unsigned)(strlen(string) + 1)); 6013 if (p == NULL) /* not enough core */ 6014 return -1; 6015 environ[i + 1] = 0; /* new end of env. */ 6016 } 6017 else 6018 { /* name already in env. */ 6019 p = vim_realloc(environ[i], strlen(string) + 1); 6020 if (p == NULL) 6021 return -1; 6022 } 6023 sprintf(p, "%s", string); /* copy into env. */ 6024 environ[i] = p; 6025 6026 return 0; 6027 } 6028 6029 static int 6030 findenv(char *name) 6031 { 6032 char *namechar, *envchar; 6033 int i, found; 6034 6035 found = 0; 6036 for (i = 0; environ[i] && !found; i++) 6037 { 6038 envchar = environ[i]; 6039 namechar = name; 6040 while (*namechar && *namechar != '=' && (*namechar == *envchar)) 6041 { 6042 namechar++; 6043 envchar++; 6044 } 6045 found = ((*namechar == '\0' || *namechar == '=') && *envchar == '='); 6046 } 6047 return found ? i - 1 : -1; 6048 } 6049 6050 static int 6051 newenv(void) 6052 { 6053 char **env, *elem; 6054 int i, esize; 6055 6056 for (i = 0; environ[i]; i++) 6057 ; 6058 6059 esize = i + EXTRASIZE + 1; 6060 env = (char **)alloc((unsigned)(esize * sizeof (elem))); 6061 if (env == NULL) 6062 return -1; 6063 6064 for (i = 0; environ[i]; i++) 6065 { 6066 elem = (char *)alloc((unsigned)(strlen(environ[i]) + 1)); 6067 if (elem == NULL) 6068 return -1; 6069 env[i] = elem; 6070 strcpy(elem, environ[i]); 6071 } 6072 6073 env[i] = 0; 6074 environ = env; 6075 envsize = esize; 6076 return 0; 6077 } 6078 6079 static int 6080 moreenv(void) 6081 { 6082 int esize; 6083 char **env; 6084 6085 esize = envsize + EXTRASIZE; 6086 env = (char **)vim_realloc((char *)environ, esize * sizeof (*env)); 6087 if (env == 0) 6088 return -1; 6089 environ = env; 6090 envsize = esize; 6091 return 0; 6092 } 6093 6094 # ifdef USE_VIMPTY_GETENV 6095 /* 6096 * Used for mch_getenv() for Mac. 6097 */ 6098 char_u * 6099 vimpty_getenv(const char_u *string) 6100 { 6101 int i; 6102 char_u *p; 6103 6104 if (envsize < 0) 6105 return NULL; 6106 6107 i = findenv((char *)string); 6108 6109 if (i < 0) 6110 return NULL; 6111 6112 p = vim_strchr((char_u *)environ[i], '='); 6113 return (p + 1); 6114 } 6115 # endif 6116 6117 #endif /* !defined(HAVE_SETENV) && !defined(HAVE_PUTENV) */ 6118 6119 #if defined(FEAT_EVAL) || defined(FEAT_SPELL) || defined(PROTO) 6120 /* 6121 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have 6122 * rights to write into. 6123 */ 6124 int 6125 filewritable(char_u *fname) 6126 { 6127 int retval = 0; 6128 #if defined(UNIX) || defined(VMS) 6129 int perm = 0; 6130 #endif 6131 6132 #if defined(UNIX) || defined(VMS) 6133 perm = mch_getperm(fname); 6134 #endif 6135 if ( 6136 # ifdef WIN3264 6137 mch_writable(fname) && 6138 # else 6139 # if defined(UNIX) || defined(VMS) 6140 (perm & 0222) && 6141 # endif 6142 # endif 6143 mch_access((char *)fname, W_OK) == 0 6144 ) 6145 { 6146 ++retval; 6147 if (mch_isdir(fname)) 6148 ++retval; 6149 } 6150 return retval; 6151 } 6152 #endif 6153 6154 #if defined(FEAT_SPELL) || defined(FEAT_PERSISTENT_UNDO) || defined(PROTO) 6155 /* 6156 * Read 2 bytes from "fd" and turn them into an int, MSB first. 6157 */ 6158 int 6159 get2c(FILE *fd) 6160 { 6161 int n; 6162 6163 n = getc(fd); 6164 n = (n << 8) + getc(fd); 6165 return n; 6166 } 6167 6168 /* 6169 * Read 3 bytes from "fd" and turn them into an int, MSB first. 6170 */ 6171 int 6172 get3c(FILE *fd) 6173 { 6174 int n; 6175 6176 n = getc(fd); 6177 n = (n << 8) + getc(fd); 6178 n = (n << 8) + getc(fd); 6179 return n; 6180 } 6181 6182 /* 6183 * Read 4 bytes from "fd" and turn them into an int, MSB first. 6184 */ 6185 int 6186 get4c(FILE *fd) 6187 { 6188 /* Use unsigned rather than int otherwise result is undefined 6189 * when left-shift sets the MSB. */ 6190 unsigned n; 6191 6192 n = (unsigned)getc(fd); 6193 n = (n << 8) + (unsigned)getc(fd); 6194 n = (n << 8) + (unsigned)getc(fd); 6195 n = (n << 8) + (unsigned)getc(fd); 6196 return (int)n; 6197 } 6198 6199 /* 6200 * Read 8 bytes from "fd" and turn them into a time_T, MSB first. 6201 */ 6202 time_T 6203 get8ctime(FILE *fd) 6204 { 6205 time_T n = 0; 6206 int i; 6207 6208 for (i = 0; i < 8; ++i) 6209 n = (n << 8) + getc(fd); 6210 return n; 6211 } 6212 6213 /* 6214 * Read a string of length "cnt" from "fd" into allocated memory. 6215 * Returns NULL when out of memory or unable to read that many bytes. 6216 */ 6217 char_u * 6218 read_string(FILE *fd, int cnt) 6219 { 6220 char_u *str; 6221 int i; 6222 int c; 6223 6224 /* allocate memory */ 6225 str = alloc((unsigned)cnt + 1); 6226 if (str != NULL) 6227 { 6228 /* Read the string. Quit when running into the EOF. */ 6229 for (i = 0; i < cnt; ++i) 6230 { 6231 c = getc(fd); 6232 if (c == EOF) 6233 { 6234 vim_free(str); 6235 return NULL; 6236 } 6237 str[i] = c; 6238 } 6239 str[i] = NUL; 6240 } 6241 return str; 6242 } 6243 6244 /* 6245 * Write a number to file "fd", MSB first, in "len" bytes. 6246 */ 6247 int 6248 put_bytes(FILE *fd, long_u nr, int len) 6249 { 6250 int i; 6251 6252 for (i = len - 1; i >= 0; --i) 6253 if (putc((int)(nr >> (i * 8)), fd) == EOF) 6254 return FAIL; 6255 return OK; 6256 } 6257 6258 #ifdef _MSC_VER 6259 # if (_MSC_VER <= 1200) 6260 /* This line is required for VC6 without the service pack. Also see the 6261 * matching #pragma below. */ 6262 # pragma optimize("", off) 6263 # endif 6264 #endif 6265 6266 /* 6267 * Write time_T to file "fd" in 8 bytes. 6268 * Returns FAIL when the write failed. 6269 */ 6270 int 6271 put_time(FILE *fd, time_T the_time) 6272 { 6273 char_u buf[8]; 6274 6275 time_to_bytes(the_time, buf); 6276 return fwrite(buf, (size_t)8, (size_t)1, fd) == 1 ? OK : FAIL; 6277 } 6278 6279 /* 6280 * Write time_T to "buf[8]". 6281 */ 6282 void 6283 time_to_bytes(time_T the_time, char_u *buf) 6284 { 6285 int c; 6286 int i; 6287 int bi = 0; 6288 time_T wtime = the_time; 6289 6290 /* time_T can be up to 8 bytes in size, more than long_u, thus we 6291 * can't use put_bytes() here. 6292 * Another problem is that ">>" may do an arithmetic shift that keeps the 6293 * sign. This happens for large values of wtime. A cast to long_u may 6294 * truncate if time_T is 8 bytes. So only use a cast when it is 4 bytes, 6295 * it's safe to assume that long_u is 4 bytes or more and when using 8 6296 * bytes the top bit won't be set. */ 6297 for (i = 7; i >= 0; --i) 6298 { 6299 if (i + 1 > (int)sizeof(time_T)) 6300 /* ">>" doesn't work well when shifting more bits than avail */ 6301 buf[bi++] = 0; 6302 else 6303 { 6304 #if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4 6305 c = (int)(wtime >> (i * 8)); 6306 #else 6307 c = (int)((long_u)wtime >> (i * 8)); 6308 #endif 6309 buf[bi++] = c; 6310 } 6311 } 6312 } 6313 6314 #ifdef _MSC_VER 6315 # if (_MSC_VER <= 1200) 6316 # pragma optimize("", on) 6317 # endif 6318 #endif 6319 6320 #endif 6321 6322 #if (defined(FEAT_MBYTE) && defined(FEAT_QUICKFIX)) \ 6323 || defined(FEAT_SPELL) || defined(PROTO) 6324 /* 6325 * Return TRUE if string "s" contains a non-ASCII character (128 or higher). 6326 * When "s" is NULL FALSE is returned. 6327 */ 6328 int 6329 has_non_ascii(char_u *s) 6330 { 6331 char_u *p; 6332 6333 if (s != NULL) 6334 for (p = s; *p != NUL; ++p) 6335 if (*p >= 128) 6336 return TRUE; 6337 return FALSE; 6338 } 6339 #endif 6340 6341 #if defined(MESSAGE_QUEUE) || defined(PROTO) 6342 /* 6343 * Process messages that have been queued for netbeans or clientserver. 6344 * Also check if any jobs have ended. 6345 * These functions can call arbitrary vimscript and should only be called when 6346 * it is safe to do so. 6347 */ 6348 void 6349 parse_queued_messages(void) 6350 { 6351 win_T *old_curwin = curwin; 6352 6353 /* For Win32 mch_breakcheck() does not check for input, do it here. */ 6354 # if defined(WIN32) && defined(FEAT_JOB_CHANNEL) 6355 channel_handle_events(FALSE); 6356 # endif 6357 6358 # ifdef FEAT_NETBEANS_INTG 6359 /* Process the queued netbeans messages. */ 6360 netbeans_parse_messages(); 6361 # endif 6362 # ifdef FEAT_JOB_CHANNEL 6363 /* Write any buffer lines still to be written. */ 6364 channel_write_any_lines(); 6365 6366 /* Process the messages queued on channels. */ 6367 channel_parse_messages(); 6368 # endif 6369 # if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) 6370 /* Process the queued clientserver messages. */ 6371 server_parse_messages(); 6372 # endif 6373 # ifdef FEAT_JOB_CHANNEL 6374 /* Check if any jobs have ended. */ 6375 job_check_ended(); 6376 # endif 6377 6378 /* If the current window changed we need to bail out of the waiting loop. 6379 * E.g. when a job exit callback closes the terminal window. */ 6380 if (curwin != old_curwin) 6381 ins_char_typebuf(K_IGNORE); 6382 } 6383 #endif 6384 6385 #ifndef PROTO /* proto is defined in vim.h */ 6386 # ifdef ELAPSED_TIMEVAL 6387 /* 6388 * Return time in msec since "start_tv". 6389 */ 6390 long 6391 elapsed(struct timeval *start_tv) 6392 { 6393 struct timeval now_tv; 6394 6395 gettimeofday(&now_tv, NULL); 6396 return (now_tv.tv_sec - start_tv->tv_sec) * 1000L 6397 + (now_tv.tv_usec - start_tv->tv_usec) / 1000L; 6398 } 6399 # endif 6400 6401 # ifdef ELAPSED_TICKCOUNT 6402 /* 6403 * Return time in msec since "start_tick". 6404 */ 6405 long 6406 elapsed(DWORD start_tick) 6407 { 6408 DWORD now = GetTickCount(); 6409 6410 return (long)now - (long)start_tick; 6411 } 6412 # endif 6413 #endif 6414