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