1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * filepath.c: dealing with file names and paths. 12 */ 13 14 #include "vim.h" 15 16 #ifdef MSWIN 17 /* 18 * Functions for ":8" filename modifier: get 8.3 version of a filename. 19 */ 20 21 /* 22 * Get the short path (8.3) for the filename in "fnamep". 23 * Only works for a valid file name. 24 * When the path gets longer "fnamep" is changed and the allocated buffer 25 * is put in "bufp". 26 * *fnamelen is the length of "fnamep" and set to 0 for a nonexistent path. 27 * Returns OK on success, FAIL on failure. 28 */ 29 static int 30 get_short_pathname(char_u **fnamep, char_u **bufp, int *fnamelen) 31 { 32 int l, len; 33 WCHAR *newbuf; 34 WCHAR *wfname; 35 36 len = MAXPATHL; 37 newbuf = malloc(len * sizeof(*newbuf)); 38 if (newbuf == NULL) 39 return FAIL; 40 41 wfname = enc_to_utf16(*fnamep, NULL); 42 if (wfname == NULL) 43 { 44 vim_free(newbuf); 45 return FAIL; 46 } 47 48 l = GetShortPathNameW(wfname, newbuf, len); 49 if (l > len - 1) 50 { 51 // If that doesn't work (not enough space), then save the string 52 // and try again with a new buffer big enough. 53 WCHAR *newbuf_t = newbuf; 54 newbuf = vim_realloc(newbuf, (l + 1) * sizeof(*newbuf)); 55 if (newbuf == NULL) 56 { 57 vim_free(wfname); 58 vim_free(newbuf_t); 59 return FAIL; 60 } 61 // Really should always succeed, as the buffer is big enough. 62 l = GetShortPathNameW(wfname, newbuf, l+1); 63 } 64 if (l != 0) 65 { 66 char_u *p = utf16_to_enc(newbuf, NULL); 67 68 if (p != NULL) 69 { 70 vim_free(*bufp); 71 *fnamep = *bufp = p; 72 } 73 else 74 { 75 vim_free(wfname); 76 vim_free(newbuf); 77 return FAIL; 78 } 79 } 80 vim_free(wfname); 81 vim_free(newbuf); 82 83 *fnamelen = l == 0 ? l : (int)STRLEN(*bufp); 84 return OK; 85 } 86 87 /* 88 * Get the short path (8.3) for the filename in "fname". The converted 89 * path is returned in "bufp". 90 * 91 * Some of the directories specified in "fname" may not exist. This function 92 * will shorten the existing directories at the beginning of the path and then 93 * append the remaining non-existing path. 94 * 95 * fname - Pointer to the filename to shorten. On return, contains the 96 * pointer to the shortened pathname 97 * bufp - Pointer to an allocated buffer for the filename. 98 * fnamelen - Length of the filename pointed to by fname 99 * 100 * Returns OK on success (or nothing done) and FAIL on failure (out of memory). 101 */ 102 static int 103 shortpath_for_invalid_fname( 104 char_u **fname, 105 char_u **bufp, 106 int *fnamelen) 107 { 108 char_u *short_fname, *save_fname, *pbuf_unused; 109 char_u *endp, *save_endp; 110 char_u ch; 111 int old_len, len; 112 int new_len, sfx_len; 113 int retval = OK; 114 115 // Make a copy 116 old_len = *fnamelen; 117 save_fname = vim_strnsave(*fname, old_len); 118 pbuf_unused = NULL; 119 short_fname = NULL; 120 121 endp = save_fname + old_len - 1; // Find the end of the copy 122 save_endp = endp; 123 124 /* 125 * Try shortening the supplied path till it succeeds by removing one 126 * directory at a time from the tail of the path. 127 */ 128 len = 0; 129 for (;;) 130 { 131 // go back one path-separator 132 while (endp > save_fname && !after_pathsep(save_fname, endp + 1)) 133 --endp; 134 if (endp <= save_fname) 135 break; // processed the complete path 136 137 /* 138 * Replace the path separator with a NUL and try to shorten the 139 * resulting path. 140 */ 141 ch = *endp; 142 *endp = 0; 143 short_fname = save_fname; 144 len = (int)STRLEN(short_fname) + 1; 145 if (get_short_pathname(&short_fname, &pbuf_unused, &len) == FAIL) 146 { 147 retval = FAIL; 148 goto theend; 149 } 150 *endp = ch; // preserve the string 151 152 if (len > 0) 153 break; // successfully shortened the path 154 155 // failed to shorten the path. Skip the path separator 156 --endp; 157 } 158 159 if (len > 0) 160 { 161 /* 162 * Succeeded in shortening the path. Now concatenate the shortened 163 * path with the remaining path at the tail. 164 */ 165 166 // Compute the length of the new path. 167 sfx_len = (int)(save_endp - endp) + 1; 168 new_len = len + sfx_len; 169 170 *fnamelen = new_len; 171 vim_free(*bufp); 172 if (new_len > old_len) 173 { 174 // There is not enough space in the currently allocated string, 175 // copy it to a buffer big enough. 176 *fname = *bufp = vim_strnsave(short_fname, new_len); 177 if (*fname == NULL) 178 { 179 retval = FAIL; 180 goto theend; 181 } 182 } 183 else 184 { 185 // Transfer short_fname to the main buffer (it's big enough), 186 // unless get_short_pathname() did its work in-place. 187 *fname = *bufp = save_fname; 188 if (short_fname != save_fname) 189 vim_strncpy(save_fname, short_fname, len); 190 save_fname = NULL; 191 } 192 193 // concat the not-shortened part of the path 194 vim_strncpy(*fname + len, endp, sfx_len); 195 (*fname)[new_len] = NUL; 196 } 197 198 theend: 199 vim_free(pbuf_unused); 200 vim_free(save_fname); 201 202 return retval; 203 } 204 205 /* 206 * Get a pathname for a partial path. 207 * Returns OK for success, FAIL for failure. 208 */ 209 static int 210 shortpath_for_partial( 211 char_u **fnamep, 212 char_u **bufp, 213 int *fnamelen) 214 { 215 int sepcount, len, tflen; 216 char_u *p; 217 char_u *pbuf, *tfname; 218 int hasTilde; 219 220 // Count up the path separators from the RHS.. so we know which part 221 // of the path to return. 222 sepcount = 0; 223 for (p = *fnamep; p < *fnamep + *fnamelen; MB_PTR_ADV(p)) 224 if (vim_ispathsep(*p)) 225 ++sepcount; 226 227 // Need full path first (use expand_env() to remove a "~/") 228 hasTilde = (**fnamep == '~'); 229 if (hasTilde) 230 pbuf = tfname = expand_env_save(*fnamep); 231 else 232 pbuf = tfname = FullName_save(*fnamep, FALSE); 233 234 len = tflen = (int)STRLEN(tfname); 235 236 if (get_short_pathname(&tfname, &pbuf, &len) == FAIL) 237 return FAIL; 238 239 if (len == 0) 240 { 241 // Don't have a valid filename, so shorten the rest of the 242 // path if we can. This CAN give us invalid 8.3 filenames, but 243 // there's not a lot of point in guessing what it might be. 244 len = tflen; 245 if (shortpath_for_invalid_fname(&tfname, &pbuf, &len) == FAIL) 246 return FAIL; 247 } 248 249 // Count the paths backward to find the beginning of the desired string. 250 for (p = tfname + len - 1; p >= tfname; --p) 251 { 252 if (has_mbyte) 253 p -= mb_head_off(tfname, p); 254 if (vim_ispathsep(*p)) 255 { 256 if (sepcount == 0 || (hasTilde && sepcount == 1)) 257 break; 258 else 259 sepcount --; 260 } 261 } 262 if (hasTilde) 263 { 264 --p; 265 if (p >= tfname) 266 *p = '~'; 267 else 268 return FAIL; 269 } 270 else 271 ++p; 272 273 // Copy in the string - p indexes into tfname - allocated at pbuf 274 vim_free(*bufp); 275 *fnamelen = (int)STRLEN(p); 276 *bufp = pbuf; 277 *fnamep = p; 278 279 return OK; 280 } 281 #endif // MSWIN 282 283 /* 284 * Adjust a filename, according to a string of modifiers. 285 * *fnamep must be NUL terminated when called. When returning, the length is 286 * determined by *fnamelen. 287 * Returns VALID_ flags or -1 for failure. 288 * When there is an error, *fnamep is set to NULL. 289 */ 290 int 291 modify_fname( 292 char_u *src, // string with modifiers 293 int tilde_file, // "~" is a file name, not $HOME 294 int *usedlen, // characters after src that are used 295 char_u **fnamep, // file name so far 296 char_u **bufp, // buffer for allocated file name or NULL 297 int *fnamelen) // length of fnamep 298 { 299 int valid = 0; 300 char_u *tail; 301 char_u *s, *p, *pbuf; 302 char_u dirname[MAXPATHL]; 303 int c; 304 int has_fullname = 0; 305 int has_homerelative = 0; 306 #ifdef MSWIN 307 char_u *fname_start = *fnamep; 308 int has_shortname = 0; 309 #endif 310 311 repeat: 312 // ":p" - full path/file_name 313 if (src[*usedlen] == ':' && src[*usedlen + 1] == 'p') 314 { 315 has_fullname = 1; 316 317 valid |= VALID_PATH; 318 *usedlen += 2; 319 320 // Expand "~/path" for all systems and "~user/path" for Unix and VMS 321 if ((*fnamep)[0] == '~' 322 #if !defined(UNIX) && !(defined(VMS) && defined(USER_HOME)) 323 && ((*fnamep)[1] == '/' 324 # ifdef BACKSLASH_IN_FILENAME 325 || (*fnamep)[1] == '\\' 326 # endif 327 || (*fnamep)[1] == NUL) 328 #endif 329 && !(tilde_file && (*fnamep)[1] == NUL) 330 ) 331 { 332 *fnamep = expand_env_save(*fnamep); 333 vim_free(*bufp); // free any allocated file name 334 *bufp = *fnamep; 335 if (*fnamep == NULL) 336 return -1; 337 } 338 339 // When "/." or "/.." is used: force expansion to get rid of it. 340 for (p = *fnamep; *p != NUL; MB_PTR_ADV(p)) 341 { 342 if (vim_ispathsep(*p) 343 && p[1] == '.' 344 && (p[2] == NUL 345 || vim_ispathsep(p[2]) 346 || (p[2] == '.' 347 && (p[3] == NUL || vim_ispathsep(p[3]))))) 348 break; 349 } 350 351 // FullName_save() is slow, don't use it when not needed. 352 if (*p != NUL || !vim_isAbsName(*fnamep)) 353 { 354 *fnamep = FullName_save(*fnamep, *p != NUL); 355 vim_free(*bufp); // free any allocated file name 356 *bufp = *fnamep; 357 if (*fnamep == NULL) 358 return -1; 359 } 360 361 #ifdef MSWIN 362 # if _WIN32_WINNT >= 0x0500 363 if (vim_strchr(*fnamep, '~') != NULL) 364 { 365 // Expand 8.3 filename to full path. Needed to make sure the same 366 // file does not have two different names. 367 // Note: problem does not occur if _WIN32_WINNT < 0x0500. 368 WCHAR *wfname = enc_to_utf16(*fnamep, NULL); 369 WCHAR buf[_MAX_PATH]; 370 371 if (wfname != NULL) 372 { 373 if (GetLongPathNameW(wfname, buf, _MAX_PATH)) 374 { 375 char_u *p = utf16_to_enc(buf, NULL); 376 377 if (p != NULL) 378 { 379 vim_free(*bufp); // free any allocated file name 380 *bufp = *fnamep = p; 381 } 382 } 383 vim_free(wfname); 384 } 385 } 386 # endif 387 #endif 388 // Append a path separator to a directory. 389 if (mch_isdir(*fnamep)) 390 { 391 // Make room for one or two extra characters. 392 *fnamep = vim_strnsave(*fnamep, STRLEN(*fnamep) + 2); 393 vim_free(*bufp); // free any allocated file name 394 *bufp = *fnamep; 395 if (*fnamep == NULL) 396 return -1; 397 add_pathsep(*fnamep); 398 } 399 } 400 401 // ":." - path relative to the current directory 402 // ":~" - path relative to the home directory 403 // ":8" - shortname path - postponed till after 404 while (src[*usedlen] == ':' 405 && ((c = src[*usedlen + 1]) == '.' || c == '~' || c == '8')) 406 { 407 *usedlen += 2; 408 if (c == '8') 409 { 410 #ifdef MSWIN 411 has_shortname = 1; // Postpone this. 412 #endif 413 continue; 414 } 415 pbuf = NULL; 416 // Need full path first (use expand_env() to remove a "~/") 417 if (!has_fullname && !has_homerelative) 418 { 419 if ((c == '.' || c == '~') && **fnamep == '~') 420 p = pbuf = expand_env_save(*fnamep); 421 else 422 p = pbuf = FullName_save(*fnamep, FALSE); 423 } 424 else 425 p = *fnamep; 426 427 has_fullname = 0; 428 429 if (p != NULL) 430 { 431 if (c == '.') 432 { 433 size_t namelen; 434 435 mch_dirname(dirname, MAXPATHL); 436 if (has_homerelative) 437 { 438 s = vim_strsave(dirname); 439 if (s != NULL) 440 { 441 home_replace(NULL, s, dirname, MAXPATHL, TRUE); 442 vim_free(s); 443 } 444 } 445 namelen = STRLEN(dirname); 446 447 // Do not call shorten_fname() here since it removes the prefix 448 // even though the path does not have a prefix. 449 if (fnamencmp(p, dirname, namelen) == 0) 450 { 451 p += namelen; 452 if (vim_ispathsep(*p)) 453 { 454 while (*p && vim_ispathsep(*p)) 455 ++p; 456 *fnamep = p; 457 if (pbuf != NULL) 458 { 459 // free any allocated file name 460 vim_free(*bufp); 461 *bufp = pbuf; 462 pbuf = NULL; 463 } 464 } 465 } 466 } 467 else 468 { 469 home_replace(NULL, p, dirname, MAXPATHL, TRUE); 470 // Only replace it when it starts with '~' 471 if (*dirname == '~') 472 { 473 s = vim_strsave(dirname); 474 if (s != NULL) 475 { 476 *fnamep = s; 477 vim_free(*bufp); 478 *bufp = s; 479 has_homerelative = TRUE; 480 } 481 } 482 } 483 vim_free(pbuf); 484 } 485 } 486 487 tail = gettail(*fnamep); 488 *fnamelen = (int)STRLEN(*fnamep); 489 490 // ":h" - head, remove "/file_name", can be repeated 491 // Don't remove the first "/" or "c:\" 492 while (src[*usedlen] == ':' && src[*usedlen + 1] == 'h') 493 { 494 valid |= VALID_HEAD; 495 *usedlen += 2; 496 s = get_past_head(*fnamep); 497 while (tail > s && after_pathsep(s, tail)) 498 MB_PTR_BACK(*fnamep, tail); 499 *fnamelen = (int)(tail - *fnamep); 500 #ifdef VMS 501 if (*fnamelen > 0) 502 *fnamelen += 1; // the path separator is part of the path 503 #endif 504 if (*fnamelen == 0) 505 { 506 // Result is empty. Turn it into "." to make ":cd %:h" work. 507 p = vim_strsave((char_u *)"."); 508 if (p == NULL) 509 return -1; 510 vim_free(*bufp); 511 *bufp = *fnamep = tail = p; 512 *fnamelen = 1; 513 } 514 else 515 { 516 while (tail > s && !after_pathsep(s, tail)) 517 MB_PTR_BACK(*fnamep, tail); 518 } 519 } 520 521 // ":8" - shortname 522 if (src[*usedlen] == ':' && src[*usedlen + 1] == '8') 523 { 524 *usedlen += 2; 525 #ifdef MSWIN 526 has_shortname = 1; 527 #endif 528 } 529 530 #ifdef MSWIN 531 /* 532 * Handle ":8" after we have done 'heads' and before we do 'tails'. 533 */ 534 if (has_shortname) 535 { 536 // Copy the string if it is shortened by :h and when it wasn't copied 537 // yet, because we are going to change it in place. Avoids changing 538 // the buffer name for "%:8". 539 if (*fnamelen < (int)STRLEN(*fnamep) || *fnamep == fname_start) 540 { 541 p = vim_strnsave(*fnamep, *fnamelen); 542 if (p == NULL) 543 return -1; 544 vim_free(*bufp); 545 *bufp = *fnamep = p; 546 } 547 548 // Split into two implementations - makes it easier. First is where 549 // there isn't a full name already, second is where there is. 550 if (!has_fullname && !vim_isAbsName(*fnamep)) 551 { 552 if (shortpath_for_partial(fnamep, bufp, fnamelen) == FAIL) 553 return -1; 554 } 555 else 556 { 557 int l = *fnamelen; 558 559 // Simple case, already have the full-name. 560 // Nearly always shorter, so try first time. 561 if (get_short_pathname(fnamep, bufp, &l) == FAIL) 562 return -1; 563 564 if (l == 0) 565 { 566 // Couldn't find the filename, search the paths. 567 l = *fnamelen; 568 if (shortpath_for_invalid_fname(fnamep, bufp, &l) == FAIL) 569 return -1; 570 } 571 *fnamelen = l; 572 } 573 } 574 #endif // MSWIN 575 576 // ":t" - tail, just the basename 577 if (src[*usedlen] == ':' && src[*usedlen + 1] == 't') 578 { 579 *usedlen += 2; 580 *fnamelen -= (int)(tail - *fnamep); 581 *fnamep = tail; 582 } 583 584 // ":e" - extension, can be repeated 585 // ":r" - root, without extension, can be repeated 586 while (src[*usedlen] == ':' 587 && (src[*usedlen + 1] == 'e' || src[*usedlen + 1] == 'r')) 588 { 589 // find a '.' in the tail: 590 // - for second :e: before the current fname 591 // - otherwise: The last '.' 592 if (src[*usedlen + 1] == 'e' && *fnamep > tail) 593 s = *fnamep - 2; 594 else 595 s = *fnamep + *fnamelen - 1; 596 for ( ; s > tail; --s) 597 if (s[0] == '.') 598 break; 599 if (src[*usedlen + 1] == 'e') // :e 600 { 601 if (s > tail) 602 { 603 *fnamelen += (int)(*fnamep - (s + 1)); 604 *fnamep = s + 1; 605 #ifdef VMS 606 // cut version from the extension 607 s = *fnamep + *fnamelen - 1; 608 for ( ; s > *fnamep; --s) 609 if (s[0] == ';') 610 break; 611 if (s > *fnamep) 612 *fnamelen = s - *fnamep; 613 #endif 614 } 615 else if (*fnamep <= tail) 616 *fnamelen = 0; 617 } 618 else // :r 619 { 620 char_u *limit = *fnamep; 621 622 if (limit < tail) 623 limit = tail; 624 if (s > limit) // remove one extension 625 *fnamelen = (int)(s - *fnamep); 626 } 627 *usedlen += 2; 628 } 629 630 // ":s?pat?foo?" - substitute 631 // ":gs?pat?foo?" - global substitute 632 if (src[*usedlen] == ':' 633 && (src[*usedlen + 1] == 's' 634 || (src[*usedlen + 1] == 'g' && src[*usedlen + 2] == 's'))) 635 { 636 char_u *str; 637 char_u *pat; 638 char_u *sub; 639 int sep; 640 char_u *flags; 641 int didit = FALSE; 642 643 flags = (char_u *)""; 644 s = src + *usedlen + 2; 645 if (src[*usedlen + 1] == 'g') 646 { 647 flags = (char_u *)"g"; 648 ++s; 649 } 650 651 sep = *s++; 652 if (sep) 653 { 654 // find end of pattern 655 p = vim_strchr(s, sep); 656 if (p != NULL) 657 { 658 pat = vim_strnsave(s, p - s); 659 if (pat != NULL) 660 { 661 s = p + 1; 662 // find end of substitution 663 p = vim_strchr(s, sep); 664 if (p != NULL) 665 { 666 sub = vim_strnsave(s, p - s); 667 str = vim_strnsave(*fnamep, *fnamelen); 668 if (sub != NULL && str != NULL) 669 { 670 *usedlen = (int)(p + 1 - src); 671 s = do_string_sub(str, pat, sub, NULL, flags); 672 if (s != NULL) 673 { 674 *fnamep = s; 675 *fnamelen = (int)STRLEN(s); 676 vim_free(*bufp); 677 *bufp = s; 678 didit = TRUE; 679 } 680 } 681 vim_free(sub); 682 vim_free(str); 683 } 684 vim_free(pat); 685 } 686 } 687 // after using ":s", repeat all the modifiers 688 if (didit) 689 goto repeat; 690 } 691 } 692 693 if (src[*usedlen] == ':' && src[*usedlen + 1] == 'S') 694 { 695 // vim_strsave_shellescape() needs a NUL terminated string. 696 c = (*fnamep)[*fnamelen]; 697 if (c != NUL) 698 (*fnamep)[*fnamelen] = NUL; 699 p = vim_strsave_shellescape(*fnamep, FALSE, FALSE); 700 if (c != NUL) 701 (*fnamep)[*fnamelen] = c; 702 if (p == NULL) 703 return -1; 704 vim_free(*bufp); 705 *bufp = *fnamep = p; 706 *fnamelen = (int)STRLEN(p); 707 *usedlen += 2; 708 } 709 710 return valid; 711 } 712 713 #if defined(FEAT_EVAL) || defined(PROTO) 714 715 /* 716 * "chdir(dir)" function 717 */ 718 void 719 f_chdir(typval_T *argvars, typval_T *rettv) 720 { 721 char_u *cwd; 722 cdscope_T scope = CDSCOPE_GLOBAL; 723 724 rettv->v_type = VAR_STRING; 725 rettv->vval.v_string = NULL; 726 727 if (argvars[0].v_type != VAR_STRING) 728 // Returning an empty string means it failed. 729 // No error message, for historic reasons. 730 return; 731 732 // Return the current directory 733 cwd = alloc(MAXPATHL); 734 if (cwd != NULL) 735 { 736 if (mch_dirname(cwd, MAXPATHL) != FAIL) 737 { 738 #ifdef BACKSLASH_IN_FILENAME 739 slash_adjust(cwd); 740 #endif 741 rettv->vval.v_string = vim_strsave(cwd); 742 } 743 vim_free(cwd); 744 } 745 746 if (curwin->w_localdir != NULL) 747 scope = CDSCOPE_WINDOW; 748 else if (curtab->tp_localdir != NULL) 749 scope = CDSCOPE_TABPAGE; 750 751 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope)) 752 // Directory change failed 753 VIM_CLEAR(rettv->vval.v_string); 754 } 755 756 /* 757 * "delete()" function 758 */ 759 void 760 f_delete(typval_T *argvars, typval_T *rettv) 761 { 762 char_u nbuf[NUMBUFLEN]; 763 char_u *name; 764 char_u *flags; 765 766 rettv->vval.v_number = -1; 767 if (check_restricted() || check_secure()) 768 return; 769 770 name = tv_get_string(&argvars[0]); 771 if (name == NULL || *name == NUL) 772 { 773 emsg(_(e_invarg)); 774 return; 775 } 776 777 if (argvars[1].v_type != VAR_UNKNOWN) 778 flags = tv_get_string_buf(&argvars[1], nbuf); 779 else 780 flags = (char_u *)""; 781 782 if (*flags == NUL) 783 // delete a file 784 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1; 785 else if (STRCMP(flags, "d") == 0) 786 // delete an empty directory 787 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1; 788 else if (STRCMP(flags, "rf") == 0) 789 // delete a directory recursively 790 rettv->vval.v_number = delete_recursive(name); 791 else 792 semsg(_(e_invexpr2), flags); 793 } 794 795 /* 796 * "executable()" function 797 */ 798 void 799 f_executable(typval_T *argvars, typval_T *rettv) 800 { 801 char_u *name = tv_get_string(&argvars[0]); 802 803 // Check in $PATH and also check directly if there is a directory name. 804 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE); 805 } 806 807 /* 808 * "exepath()" function 809 */ 810 void 811 f_exepath(typval_T *argvars, typval_T *rettv) 812 { 813 char_u *p = NULL; 814 815 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE); 816 rettv->v_type = VAR_STRING; 817 rettv->vval.v_string = p; 818 } 819 820 /* 821 * "filereadable()" function 822 */ 823 void 824 f_filereadable(typval_T *argvars, typval_T *rettv) 825 { 826 int fd; 827 char_u *p; 828 int n; 829 830 #ifndef O_NONBLOCK 831 # define O_NONBLOCK 0 832 #endif 833 p = tv_get_string(&argvars[0]); 834 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p, 835 O_RDONLY | O_NONBLOCK, 0)) >= 0) 836 { 837 n = TRUE; 838 close(fd); 839 } 840 else 841 n = FALSE; 842 843 rettv->vval.v_number = n; 844 } 845 846 /* 847 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have 848 * rights to write into. 849 */ 850 void 851 f_filewritable(typval_T *argvars, typval_T *rettv) 852 { 853 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0])); 854 } 855 856 static void 857 findfilendir( 858 typval_T *argvars UNUSED, 859 typval_T *rettv, 860 int find_what UNUSED) 861 { 862 #ifdef FEAT_SEARCHPATH 863 char_u *fname; 864 char_u *fresult = NULL; 865 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; 866 char_u *p; 867 char_u pathbuf[NUMBUFLEN]; 868 int count = 1; 869 int first = TRUE; 870 int error = FALSE; 871 #endif 872 873 rettv->vval.v_string = NULL; 874 rettv->v_type = VAR_STRING; 875 876 #ifdef FEAT_SEARCHPATH 877 fname = tv_get_string(&argvars[0]); 878 879 if (argvars[1].v_type != VAR_UNKNOWN) 880 { 881 p = tv_get_string_buf_chk(&argvars[1], pathbuf); 882 if (p == NULL) 883 error = TRUE; 884 else 885 { 886 if (*p != NUL) 887 path = p; 888 889 if (argvars[2].v_type != VAR_UNKNOWN) 890 count = (int)tv_get_number_chk(&argvars[2], &error); 891 } 892 } 893 894 if (count < 0 && rettv_list_alloc(rettv) == FAIL) 895 error = TRUE; 896 897 if (*fname != NUL && !error) 898 { 899 do 900 { 901 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) 902 vim_free(fresult); 903 fresult = find_file_in_path_option(first ? fname : NULL, 904 first ? (int)STRLEN(fname) : 0, 905 0, first, path, 906 find_what, 907 curbuf->b_ffname, 908 find_what == FINDFILE_DIR 909 ? (char_u *)"" : curbuf->b_p_sua); 910 first = FALSE; 911 912 if (fresult != NULL && rettv->v_type == VAR_LIST) 913 list_append_string(rettv->vval.v_list, fresult, -1); 914 915 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL); 916 } 917 918 if (rettv->v_type == VAR_STRING) 919 rettv->vval.v_string = fresult; 920 #endif 921 } 922 923 /* 924 * "finddir({fname}[, {path}[, {count}]])" function 925 */ 926 void 927 f_finddir(typval_T *argvars, typval_T *rettv) 928 { 929 findfilendir(argvars, rettv, FINDFILE_DIR); 930 } 931 932 /* 933 * "findfile({fname}[, {path}[, {count}]])" function 934 */ 935 void 936 f_findfile(typval_T *argvars, typval_T *rettv) 937 { 938 findfilendir(argvars, rettv, FINDFILE_FILE); 939 } 940 941 /* 942 * "fnamemodify({fname}, {mods})" function 943 */ 944 void 945 f_fnamemodify(typval_T *argvars, typval_T *rettv) 946 { 947 char_u *fname; 948 char_u *mods; 949 int usedlen = 0; 950 int len; 951 char_u *fbuf = NULL; 952 char_u buf[NUMBUFLEN]; 953 954 fname = tv_get_string_chk(&argvars[0]); 955 mods = tv_get_string_buf_chk(&argvars[1], buf); 956 if (fname == NULL || mods == NULL) 957 fname = NULL; 958 else 959 { 960 len = (int)STRLEN(fname); 961 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len); 962 } 963 964 rettv->v_type = VAR_STRING; 965 if (fname == NULL) 966 rettv->vval.v_string = NULL; 967 else 968 rettv->vval.v_string = vim_strnsave(fname, len); 969 vim_free(fbuf); 970 } 971 972 /* 973 * "getcwd()" function 974 * 975 * Return the current working directory of a window in a tab page. 976 * First optional argument 'winnr' is the window number or -1 and the second 977 * optional argument 'tabnr' is the tab page number. 978 * 979 * If no arguments are supplied, then return the directory of the current 980 * window. 981 * If only 'winnr' is specified and is not -1 or 0 then return the directory of 982 * the specified window. 983 * If 'winnr' is 0 then return the directory of the current window. 984 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the 985 * directory of the specified tab page. Otherwise return the directory of the 986 * specified window in the specified tab page. 987 * If the window or the tab page doesn't exist then return NULL. 988 */ 989 void 990 f_getcwd(typval_T *argvars, typval_T *rettv) 991 { 992 win_T *wp = NULL; 993 tabpage_T *tp = NULL; 994 char_u *cwd; 995 int global = FALSE; 996 997 rettv->v_type = VAR_STRING; 998 rettv->vval.v_string = NULL; 999 1000 if (argvars[0].v_type == VAR_NUMBER 1001 && argvars[0].vval.v_number == -1 1002 && argvars[1].v_type == VAR_UNKNOWN) 1003 global = TRUE; 1004 else 1005 wp = find_tabwin(&argvars[0], &argvars[1], &tp); 1006 1007 if (wp != NULL && wp->w_localdir != NULL) 1008 rettv->vval.v_string = vim_strsave(wp->w_localdir); 1009 else if (tp != NULL && tp->tp_localdir != NULL) 1010 rettv->vval.v_string = vim_strsave(tp->tp_localdir); 1011 else if (wp != NULL || tp != NULL || global) 1012 { 1013 if (globaldir != NULL) 1014 rettv->vval.v_string = vim_strsave(globaldir); 1015 else 1016 { 1017 cwd = alloc(MAXPATHL); 1018 if (cwd != NULL) 1019 { 1020 if (mch_dirname(cwd, MAXPATHL) != FAIL) 1021 rettv->vval.v_string = vim_strsave(cwd); 1022 vim_free(cwd); 1023 } 1024 } 1025 } 1026 #ifdef BACKSLASH_IN_FILENAME 1027 if (rettv->vval.v_string != NULL) 1028 slash_adjust(rettv->vval.v_string); 1029 #endif 1030 } 1031 1032 /* 1033 * Convert "st" to file permission string. 1034 */ 1035 char_u * 1036 getfpermst(stat_T *st, char_u *perm) 1037 { 1038 char_u flags[] = "rwx"; 1039 int i; 1040 1041 for (i = 0; i < 9; i++) 1042 { 1043 if (st->st_mode & (1 << (8 - i))) 1044 perm[i] = flags[i % 3]; 1045 else 1046 perm[i] = '-'; 1047 } 1048 return perm; 1049 } 1050 1051 /* 1052 * "getfperm({fname})" function 1053 */ 1054 void 1055 f_getfperm(typval_T *argvars, typval_T *rettv) 1056 { 1057 char_u *fname; 1058 stat_T st; 1059 char_u *perm = NULL; 1060 char_u permbuf[] = "---------"; 1061 1062 fname = tv_get_string(&argvars[0]); 1063 1064 rettv->v_type = VAR_STRING; 1065 if (mch_stat((char *)fname, &st) >= 0) 1066 perm = vim_strsave(getfpermst(&st, permbuf)); 1067 rettv->vval.v_string = perm; 1068 } 1069 1070 /* 1071 * "getfsize({fname})" function 1072 */ 1073 void 1074 f_getfsize(typval_T *argvars, typval_T *rettv) 1075 { 1076 char_u *fname; 1077 stat_T st; 1078 1079 fname = tv_get_string(&argvars[0]); 1080 1081 rettv->v_type = VAR_NUMBER; 1082 1083 if (mch_stat((char *)fname, &st) >= 0) 1084 { 1085 if (mch_isdir(fname)) 1086 rettv->vval.v_number = 0; 1087 else 1088 { 1089 rettv->vval.v_number = (varnumber_T)st.st_size; 1090 1091 // non-perfect check for overflow 1092 if ((off_T)rettv->vval.v_number != (off_T)st.st_size) 1093 rettv->vval.v_number = -2; 1094 } 1095 } 1096 else 1097 rettv->vval.v_number = -1; 1098 } 1099 1100 /* 1101 * "getftime({fname})" function 1102 */ 1103 void 1104 f_getftime(typval_T *argvars, typval_T *rettv) 1105 { 1106 char_u *fname; 1107 stat_T st; 1108 1109 fname = tv_get_string(&argvars[0]); 1110 1111 if (mch_stat((char *)fname, &st) >= 0) 1112 rettv->vval.v_number = (varnumber_T)st.st_mtime; 1113 else 1114 rettv->vval.v_number = -1; 1115 } 1116 1117 /* 1118 * Convert "st" to file type string. 1119 */ 1120 char_u * 1121 getftypest(stat_T *st) 1122 { 1123 char *t; 1124 1125 if (S_ISREG(st->st_mode)) 1126 t = "file"; 1127 else if (S_ISDIR(st->st_mode)) 1128 t = "dir"; 1129 else if (S_ISLNK(st->st_mode)) 1130 t = "link"; 1131 else if (S_ISBLK(st->st_mode)) 1132 t = "bdev"; 1133 else if (S_ISCHR(st->st_mode)) 1134 t = "cdev"; 1135 else if (S_ISFIFO(st->st_mode)) 1136 t = "fifo"; 1137 else if (S_ISSOCK(st->st_mode)) 1138 t = "socket"; 1139 else 1140 t = "other"; 1141 return (char_u*)t; 1142 } 1143 1144 /* 1145 * "getftype({fname})" function 1146 */ 1147 void 1148 f_getftype(typval_T *argvars, typval_T *rettv) 1149 { 1150 char_u *fname; 1151 stat_T st; 1152 char_u *type = NULL; 1153 1154 fname = tv_get_string(&argvars[0]); 1155 1156 rettv->v_type = VAR_STRING; 1157 if (mch_lstat((char *)fname, &st) >= 0) 1158 type = vim_strsave(getftypest(&st)); 1159 rettv->vval.v_string = type; 1160 } 1161 1162 /* 1163 * "glob()" function 1164 */ 1165 void 1166 f_glob(typval_T *argvars, typval_T *rettv) 1167 { 1168 int options = WILD_SILENT|WILD_USE_NL; 1169 expand_T xpc; 1170 int error = FALSE; 1171 1172 // When the optional second argument is non-zero, don't remove matches 1173 // for 'wildignore' and don't put matches for 'suffixes' at the end. 1174 rettv->v_type = VAR_STRING; 1175 if (argvars[1].v_type != VAR_UNKNOWN) 1176 { 1177 if (tv_get_number_chk(&argvars[1], &error)) 1178 options |= WILD_KEEP_ALL; 1179 if (argvars[2].v_type != VAR_UNKNOWN) 1180 { 1181 if (tv_get_number_chk(&argvars[2], &error)) 1182 rettv_list_set(rettv, NULL); 1183 if (argvars[3].v_type != VAR_UNKNOWN 1184 && tv_get_number_chk(&argvars[3], &error)) 1185 options |= WILD_ALLLINKS; 1186 } 1187 } 1188 if (!error) 1189 { 1190 ExpandInit(&xpc); 1191 xpc.xp_context = EXPAND_FILES; 1192 if (p_wic) 1193 options += WILD_ICASE; 1194 if (rettv->v_type == VAR_STRING) 1195 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]), 1196 NULL, options, WILD_ALL); 1197 else if (rettv_list_alloc(rettv) != FAIL) 1198 { 1199 int i; 1200 1201 ExpandOne(&xpc, tv_get_string(&argvars[0]), 1202 NULL, options, WILD_ALL_KEEP); 1203 for (i = 0; i < xpc.xp_numfiles; i++) 1204 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); 1205 1206 ExpandCleanup(&xpc); 1207 } 1208 } 1209 else 1210 rettv->vval.v_string = NULL; 1211 } 1212 1213 /* 1214 * "glob2regpat()" function 1215 */ 1216 void 1217 f_glob2regpat(typval_T *argvars, typval_T *rettv) 1218 { 1219 char_u *pat = tv_get_string_chk(&argvars[0]); 1220 1221 rettv->v_type = VAR_STRING; 1222 rettv->vval.v_string = (pat == NULL) 1223 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE); 1224 } 1225 1226 /* 1227 * "globpath()" function 1228 */ 1229 void 1230 f_globpath(typval_T *argvars, typval_T *rettv) 1231 { 1232 int flags = WILD_IGNORE_COMPLETESLASH; 1233 char_u buf1[NUMBUFLEN]; 1234 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1); 1235 int error = FALSE; 1236 garray_T ga; 1237 int i; 1238 1239 // When the optional second argument is non-zero, don't remove matches 1240 // for 'wildignore' and don't put matches for 'suffixes' at the end. 1241 rettv->v_type = VAR_STRING; 1242 if (argvars[2].v_type != VAR_UNKNOWN) 1243 { 1244 if (tv_get_number_chk(&argvars[2], &error)) 1245 flags |= WILD_KEEP_ALL; 1246 if (argvars[3].v_type != VAR_UNKNOWN) 1247 { 1248 if (tv_get_number_chk(&argvars[3], &error)) 1249 rettv_list_set(rettv, NULL); 1250 if (argvars[4].v_type != VAR_UNKNOWN 1251 && tv_get_number_chk(&argvars[4], &error)) 1252 flags |= WILD_ALLLINKS; 1253 } 1254 } 1255 if (file != NULL && !error) 1256 { 1257 ga_init2(&ga, (int)sizeof(char_u *), 10); 1258 globpath(tv_get_string(&argvars[0]), file, &ga, flags); 1259 if (rettv->v_type == VAR_STRING) 1260 rettv->vval.v_string = ga_concat_strings(&ga, "\n"); 1261 else if (rettv_list_alloc(rettv) != FAIL) 1262 for (i = 0; i < ga.ga_len; ++i) 1263 list_append_string(rettv->vval.v_list, 1264 ((char_u **)(ga.ga_data))[i], -1); 1265 ga_clear_strings(&ga); 1266 } 1267 else 1268 rettv->vval.v_string = NULL; 1269 } 1270 1271 /* 1272 * "isdirectory()" function 1273 */ 1274 void 1275 f_isdirectory(typval_T *argvars, typval_T *rettv) 1276 { 1277 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0])); 1278 } 1279 1280 /* 1281 * Create the directory in which "dir" is located, and higher levels when 1282 * needed. 1283 * Return OK or FAIL. 1284 */ 1285 static int 1286 mkdir_recurse(char_u *dir, int prot) 1287 { 1288 char_u *p; 1289 char_u *updir; 1290 int r = FAIL; 1291 1292 // Get end of directory name in "dir". 1293 // We're done when it's "/" or "c:/". 1294 p = gettail_sep(dir); 1295 if (p <= get_past_head(dir)) 1296 return OK; 1297 1298 // If the directory exists we're done. Otherwise: create it. 1299 updir = vim_strnsave(dir, p - dir); 1300 if (updir == NULL) 1301 return FAIL; 1302 if (mch_isdir(updir)) 1303 r = OK; 1304 else if (mkdir_recurse(updir, prot) == OK) 1305 r = vim_mkdir_emsg(updir, prot); 1306 vim_free(updir); 1307 return r; 1308 } 1309 1310 /* 1311 * "mkdir()" function 1312 */ 1313 void 1314 f_mkdir(typval_T *argvars, typval_T *rettv) 1315 { 1316 char_u *dir; 1317 char_u buf[NUMBUFLEN]; 1318 int prot = 0755; 1319 1320 rettv->vval.v_number = FAIL; 1321 if (check_restricted() || check_secure()) 1322 return; 1323 1324 dir = tv_get_string_buf(&argvars[0], buf); 1325 if (*dir == NUL) 1326 return; 1327 1328 if (*gettail(dir) == NUL) 1329 // remove trailing slashes 1330 *gettail_sep(dir) = NUL; 1331 1332 if (argvars[1].v_type != VAR_UNKNOWN) 1333 { 1334 if (argvars[2].v_type != VAR_UNKNOWN) 1335 { 1336 prot = (int)tv_get_number_chk(&argvars[2], NULL); 1337 if (prot == -1) 1338 return; 1339 } 1340 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0) 1341 { 1342 if (mch_isdir(dir)) 1343 { 1344 // With the "p" flag it's OK if the dir already exists. 1345 rettv->vval.v_number = OK; 1346 return; 1347 } 1348 mkdir_recurse(dir, prot); 1349 } 1350 } 1351 rettv->vval.v_number = vim_mkdir_emsg(dir, prot); 1352 } 1353 1354 /* 1355 * "pathshorten()" function 1356 */ 1357 void 1358 f_pathshorten(typval_T *argvars, typval_T *rettv) 1359 { 1360 char_u *p; 1361 1362 rettv->v_type = VAR_STRING; 1363 p = tv_get_string_chk(&argvars[0]); 1364 if (p == NULL) 1365 rettv->vval.v_string = NULL; 1366 else 1367 { 1368 p = vim_strsave(p); 1369 rettv->vval.v_string = p; 1370 if (p != NULL) 1371 shorten_dir(p); 1372 } 1373 } 1374 1375 /* 1376 * Common code for readdir_checkitem() and readdirex_checkitem(). 1377 * Either "name" or "dict" is NULL. 1378 */ 1379 static int 1380 checkitem_common(void *context, char_u *name, dict_T *dict) 1381 { 1382 typval_T *expr = (typval_T *)context; 1383 typval_T save_val; 1384 typval_T rettv; 1385 typval_T argv[2]; 1386 int retval = 0; 1387 int error = FALSE; 1388 1389 prepare_vimvar(VV_VAL, &save_val); 1390 if (name != NULL) 1391 { 1392 set_vim_var_string(VV_VAL, name, -1); 1393 argv[0].v_type = VAR_STRING; 1394 argv[0].vval.v_string = name; 1395 } 1396 else 1397 { 1398 set_vim_var_dict(VV_VAL, dict); 1399 argv[0].v_type = VAR_DICT; 1400 argv[0].vval.v_dict = dict; 1401 } 1402 1403 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL) 1404 goto theend; 1405 1406 // We want to use -1, but also true/false should be allowed. 1407 if (rettv.v_type == VAR_SPECIAL || rettv.v_type == VAR_BOOL) 1408 { 1409 rettv.v_type = VAR_NUMBER; 1410 rettv.vval.v_number = rettv.vval.v_number == VVAL_TRUE; 1411 } 1412 retval = tv_get_number_chk(&rettv, &error); 1413 if (error) 1414 retval = -1; 1415 clear_tv(&rettv); 1416 1417 theend: 1418 if (name != NULL) 1419 set_vim_var_string(VV_VAL, NULL, 0); 1420 else 1421 set_vim_var_dict(VV_VAL, NULL); 1422 restore_vimvar(VV_VAL, &save_val); 1423 return retval; 1424 } 1425 1426 /* 1427 * Evaluate "expr" (= "context") for readdir(). 1428 */ 1429 static int 1430 readdir_checkitem(void *context, void *item) 1431 { 1432 char_u *name = (char_u *)item; 1433 1434 return checkitem_common(context, name, NULL); 1435 } 1436 1437 static int 1438 readdirex_dict_arg(typval_T *tv, int *cmp) 1439 { 1440 char_u *compare; 1441 1442 if (tv->v_type != VAR_DICT) 1443 { 1444 emsg(_(e_dictreq)); 1445 return FAIL; 1446 } 1447 1448 if (dict_find(tv->vval.v_dict, (char_u *)"sort", -1) != NULL) 1449 compare = dict_get_string(tv->vval.v_dict, (char_u *)"sort", FALSE); 1450 else 1451 { 1452 semsg(_(e_no_dict_key), "sort"); 1453 return FAIL; 1454 } 1455 1456 if (STRCMP(compare, (char_u *) "none") == 0) 1457 *cmp = READDIR_SORT_NONE; 1458 else if (STRCMP(compare, (char_u *) "case") == 0) 1459 *cmp = READDIR_SORT_BYTE; 1460 else if (STRCMP(compare, (char_u *) "icase") == 0) 1461 *cmp = READDIR_SORT_IC; 1462 else if (STRCMP(compare, (char_u *) "collate") == 0) 1463 *cmp = READDIR_SORT_COLLATE; 1464 return OK; 1465 } 1466 1467 /* 1468 * "readdir()" function 1469 */ 1470 void 1471 f_readdir(typval_T *argvars, typval_T *rettv) 1472 { 1473 typval_T *expr; 1474 int ret; 1475 char_u *path; 1476 char_u *p; 1477 garray_T ga; 1478 int i; 1479 int sort = READDIR_SORT_BYTE; 1480 1481 if (rettv_list_alloc(rettv) == FAIL) 1482 return; 1483 path = tv_get_string(&argvars[0]); 1484 expr = &argvars[1]; 1485 1486 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN && 1487 readdirex_dict_arg(&argvars[2], &sort) == FAIL) 1488 return; 1489 1490 ret = readdir_core(&ga, path, FALSE, (void *)expr, 1491 (expr->v_type == VAR_UNKNOWN) ? NULL : readdir_checkitem, sort); 1492 if (ret == OK) 1493 { 1494 for (i = 0; i < ga.ga_len; i++) 1495 { 1496 p = ((char_u **)ga.ga_data)[i]; 1497 list_append_string(rettv->vval.v_list, p, -1); 1498 } 1499 } 1500 ga_clear_strings(&ga); 1501 } 1502 1503 /* 1504 * Evaluate "expr" (= "context") for readdirex(). 1505 */ 1506 static int 1507 readdirex_checkitem(void *context, void *item) 1508 { 1509 dict_T *dict = (dict_T*)item; 1510 1511 return checkitem_common(context, NULL, dict); 1512 } 1513 1514 /* 1515 * "readdirex()" function 1516 */ 1517 void 1518 f_readdirex(typval_T *argvars, typval_T *rettv) 1519 { 1520 typval_T *expr; 1521 int ret; 1522 char_u *path; 1523 garray_T ga; 1524 int i; 1525 int sort = READDIR_SORT_BYTE; 1526 1527 if (rettv_list_alloc(rettv) == FAIL) 1528 return; 1529 path = tv_get_string(&argvars[0]); 1530 expr = &argvars[1]; 1531 1532 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN && 1533 readdirex_dict_arg(&argvars[2], &sort) == FAIL) 1534 return; 1535 1536 ret = readdir_core(&ga, path, TRUE, (void *)expr, 1537 (expr->v_type == VAR_UNKNOWN) ? NULL : readdirex_checkitem, sort); 1538 if (ret == OK) 1539 { 1540 for (i = 0; i < ga.ga_len; i++) 1541 { 1542 dict_T *dict = ((dict_T**)ga.ga_data)[i]; 1543 list_append_dict(rettv->vval.v_list, dict); 1544 dict_unref(dict); 1545 } 1546 } 1547 ga_clear(&ga); 1548 } 1549 1550 /* 1551 * "readfile()" function 1552 */ 1553 void 1554 f_readfile(typval_T *argvars, typval_T *rettv) 1555 { 1556 int binary = FALSE; 1557 int blob = FALSE; 1558 int failed = FALSE; 1559 char_u *fname; 1560 FILE *fd; 1561 char_u buf[(IOSIZE/256)*256]; // rounded to avoid odd + 1 1562 int io_size = sizeof(buf); 1563 int readlen; // size of last fread() 1564 char_u *prev = NULL; // previously read bytes, if any 1565 long prevlen = 0; // length of data in prev 1566 long prevsize = 0; // size of prev buffer 1567 long maxline = MAXLNUM; 1568 long cnt = 0; 1569 char_u *p; // position in buf 1570 char_u *start; // start of current line 1571 1572 if (argvars[1].v_type != VAR_UNKNOWN) 1573 { 1574 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0) 1575 binary = TRUE; 1576 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0) 1577 blob = TRUE; 1578 1579 if (argvars[2].v_type != VAR_UNKNOWN) 1580 maxline = (long)tv_get_number(&argvars[2]); 1581 } 1582 1583 if ((blob ? rettv_blob_alloc(rettv) : rettv_list_alloc(rettv)) == FAIL) 1584 return; 1585 1586 // Always open the file in binary mode, library functions have a mind of 1587 // their own about CR-LF conversion. 1588 fname = tv_get_string(&argvars[0]); 1589 1590 if (mch_isdir(fname)) 1591 { 1592 semsg(_(e_isadir2), fname); 1593 return; 1594 } 1595 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL) 1596 { 1597 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname); 1598 return; 1599 } 1600 1601 if (blob) 1602 { 1603 if (read_blob(fd, rettv->vval.v_blob) == FAIL) 1604 { 1605 semsg(_(e_notread), fname); 1606 // An empty blob is returned on error. 1607 blob_free(rettv->vval.v_blob); 1608 rettv->vval.v_blob = NULL; 1609 } 1610 fclose(fd); 1611 return; 1612 } 1613 1614 while (cnt < maxline || maxline < 0) 1615 { 1616 readlen = (int)fread(buf, 1, io_size, fd); 1617 1618 // This for loop processes what was read, but is also entered at end 1619 // of file so that either: 1620 // - an incomplete line gets written 1621 // - a "binary" file gets an empty line at the end if it ends in a 1622 // newline. 1623 for (p = buf, start = buf; 1624 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary)); 1625 ++p) 1626 { 1627 if (*p == '\n' || readlen <= 0) 1628 { 1629 listitem_T *li; 1630 char_u *s = NULL; 1631 long_u len = p - start; 1632 1633 // Finished a line. Remove CRs before NL. 1634 if (readlen > 0 && !binary) 1635 { 1636 while (len > 0 && start[len - 1] == '\r') 1637 --len; 1638 // removal may cross back to the "prev" string 1639 if (len == 0) 1640 while (prevlen > 0 && prev[prevlen - 1] == '\r') 1641 --prevlen; 1642 } 1643 if (prevlen == 0) 1644 s = vim_strnsave(start, len); 1645 else 1646 { 1647 // Change "prev" buffer to be the right size. This way 1648 // the bytes are only copied once, and very long lines are 1649 // allocated only once. 1650 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL) 1651 { 1652 mch_memmove(s + prevlen, start, len); 1653 s[prevlen + len] = NUL; 1654 prev = NULL; // the list will own the string 1655 prevlen = prevsize = 0; 1656 } 1657 } 1658 if (s == NULL) 1659 { 1660 do_outofmem_msg((long_u) prevlen + len + 1); 1661 failed = TRUE; 1662 break; 1663 } 1664 1665 if ((li = listitem_alloc()) == NULL) 1666 { 1667 vim_free(s); 1668 failed = TRUE; 1669 break; 1670 } 1671 li->li_tv.v_type = VAR_STRING; 1672 li->li_tv.v_lock = 0; 1673 li->li_tv.vval.v_string = s; 1674 list_append(rettv->vval.v_list, li); 1675 1676 start = p + 1; // step over newline 1677 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0) 1678 break; 1679 } 1680 else if (*p == NUL) 1681 *p = '\n'; 1682 // Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this 1683 // when finding the BF and check the previous two bytes. 1684 else if (*p == 0xbf && enc_utf8 && !binary) 1685 { 1686 // Find the two bytes before the 0xbf. If p is at buf, or buf 1687 // + 1, these may be in the "prev" string. 1688 char_u back1 = p >= buf + 1 ? p[-1] 1689 : prevlen >= 1 ? prev[prevlen - 1] : NUL; 1690 char_u back2 = p >= buf + 2 ? p[-2] 1691 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1] 1692 : prevlen >= 2 ? prev[prevlen - 2] : NUL; 1693 1694 if (back2 == 0xef && back1 == 0xbb) 1695 { 1696 char_u *dest = p - 2; 1697 1698 // Usually a BOM is at the beginning of a file, and so at 1699 // the beginning of a line; then we can just step over it. 1700 if (start == dest) 1701 start = p + 1; 1702 else 1703 { 1704 // have to shuffle buf to close gap 1705 int adjust_prevlen = 0; 1706 1707 if (dest < buf) 1708 { 1709 adjust_prevlen = (int)(buf - dest); // must be 1 or 2 1710 dest = buf; 1711 } 1712 if (readlen > p - buf + 1) 1713 mch_memmove(dest, p + 1, readlen - (p - buf) - 1); 1714 readlen -= 3 - adjust_prevlen; 1715 prevlen -= adjust_prevlen; 1716 p = dest - 1; 1717 } 1718 } 1719 } 1720 } // for 1721 1722 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0) 1723 break; 1724 if (start < p) 1725 { 1726 // There's part of a line in buf, store it in "prev". 1727 if (p - start + prevlen >= prevsize) 1728 { 1729 // need bigger "prev" buffer 1730 char_u *newprev; 1731 1732 // A common use case is ordinary text files and "prev" gets a 1733 // fragment of a line, so the first allocation is made 1734 // small, to avoid repeatedly 'allocing' large and 1735 // 'reallocing' small. 1736 if (prevsize == 0) 1737 prevsize = (long)(p - start); 1738 else 1739 { 1740 long grow50pc = (prevsize * 3) / 2; 1741 long growmin = (long)((p - start) * 2 + prevlen); 1742 prevsize = grow50pc > growmin ? grow50pc : growmin; 1743 } 1744 newprev = vim_realloc(prev, prevsize); 1745 if (newprev == NULL) 1746 { 1747 do_outofmem_msg((long_u)prevsize); 1748 failed = TRUE; 1749 break; 1750 } 1751 prev = newprev; 1752 } 1753 // Add the line part to end of "prev". 1754 mch_memmove(prev + prevlen, start, p - start); 1755 prevlen += (long)(p - start); 1756 } 1757 } // while 1758 1759 // For a negative line count use only the lines at the end of the file, 1760 // free the rest. 1761 if (!failed && maxline < 0) 1762 while (cnt > -maxline) 1763 { 1764 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first); 1765 --cnt; 1766 } 1767 1768 if (failed) 1769 { 1770 // an empty list is returned on error 1771 list_free(rettv->vval.v_list); 1772 rettv_list_alloc(rettv); 1773 } 1774 1775 vim_free(prev); 1776 fclose(fd); 1777 } 1778 1779 /* 1780 * "resolve()" function 1781 */ 1782 void 1783 f_resolve(typval_T *argvars, typval_T *rettv) 1784 { 1785 char_u *p; 1786 #ifdef HAVE_READLINK 1787 char_u *buf = NULL; 1788 #endif 1789 1790 p = tv_get_string(&argvars[0]); 1791 #ifdef FEAT_SHORTCUT 1792 { 1793 char_u *v = NULL; 1794 1795 v = mch_resolve_path(p, TRUE); 1796 if (v != NULL) 1797 rettv->vval.v_string = v; 1798 else 1799 rettv->vval.v_string = vim_strsave(p); 1800 } 1801 #else 1802 # ifdef HAVE_READLINK 1803 { 1804 char_u *cpy; 1805 int len; 1806 char_u *remain = NULL; 1807 char_u *q; 1808 int is_relative_to_current = FALSE; 1809 int has_trailing_pathsep = FALSE; 1810 int limit = 100; 1811 1812 p = vim_strsave(p); 1813 if (p == NULL) 1814 goto fail; 1815 if (p[0] == '.' && (vim_ispathsep(p[1]) 1816 || (p[1] == '.' && (vim_ispathsep(p[2]))))) 1817 is_relative_to_current = TRUE; 1818 1819 len = STRLEN(p); 1820 if (len > 0 && after_pathsep(p, p + len)) 1821 { 1822 has_trailing_pathsep = TRUE; 1823 p[len - 1] = NUL; // the trailing slash breaks readlink() 1824 } 1825 1826 q = getnextcomp(p); 1827 if (*q != NUL) 1828 { 1829 // Separate the first path component in "p", and keep the 1830 // remainder (beginning with the path separator). 1831 remain = vim_strsave(q - 1); 1832 q[-1] = NUL; 1833 } 1834 1835 buf = alloc(MAXPATHL + 1); 1836 if (buf == NULL) 1837 { 1838 vim_free(p); 1839 goto fail; 1840 } 1841 1842 for (;;) 1843 { 1844 for (;;) 1845 { 1846 len = readlink((char *)p, (char *)buf, MAXPATHL); 1847 if (len <= 0) 1848 break; 1849 buf[len] = NUL; 1850 1851 if (limit-- == 0) 1852 { 1853 vim_free(p); 1854 vim_free(remain); 1855 emsg(_("E655: Too many symbolic links (cycle?)")); 1856 rettv->vval.v_string = NULL; 1857 goto fail; 1858 } 1859 1860 // Ensure that the result will have a trailing path separator 1861 // if the argument has one. 1862 if (remain == NULL && has_trailing_pathsep) 1863 add_pathsep(buf); 1864 1865 // Separate the first path component in the link value and 1866 // concatenate the remainders. 1867 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf); 1868 if (*q != NUL) 1869 { 1870 if (remain == NULL) 1871 remain = vim_strsave(q - 1); 1872 else 1873 { 1874 cpy = concat_str(q - 1, remain); 1875 if (cpy != NULL) 1876 { 1877 vim_free(remain); 1878 remain = cpy; 1879 } 1880 } 1881 q[-1] = NUL; 1882 } 1883 1884 q = gettail(p); 1885 if (q > p && *q == NUL) 1886 { 1887 // Ignore trailing path separator. 1888 q[-1] = NUL; 1889 q = gettail(p); 1890 } 1891 if (q > p && !mch_isFullName(buf)) 1892 { 1893 // symlink is relative to directory of argument 1894 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1); 1895 if (cpy != NULL) 1896 { 1897 STRCPY(cpy, p); 1898 STRCPY(gettail(cpy), buf); 1899 vim_free(p); 1900 p = cpy; 1901 } 1902 } 1903 else 1904 { 1905 vim_free(p); 1906 p = vim_strsave(buf); 1907 } 1908 } 1909 1910 if (remain == NULL) 1911 break; 1912 1913 // Append the first path component of "remain" to "p". 1914 q = getnextcomp(remain + 1); 1915 len = q - remain - (*q != NUL); 1916 cpy = vim_strnsave(p, STRLEN(p) + len); 1917 if (cpy != NULL) 1918 { 1919 STRNCAT(cpy, remain, len); 1920 vim_free(p); 1921 p = cpy; 1922 } 1923 // Shorten "remain". 1924 if (*q != NUL) 1925 STRMOVE(remain, q - 1); 1926 else 1927 VIM_CLEAR(remain); 1928 } 1929 1930 // If the result is a relative path name, make it explicitly relative to 1931 // the current directory if and only if the argument had this form. 1932 if (!vim_ispathsep(*p)) 1933 { 1934 if (is_relative_to_current 1935 && *p != NUL 1936 && !(p[0] == '.' 1937 && (p[1] == NUL 1938 || vim_ispathsep(p[1]) 1939 || (p[1] == '.' 1940 && (p[2] == NUL 1941 || vim_ispathsep(p[2])))))) 1942 { 1943 // Prepend "./". 1944 cpy = concat_str((char_u *)"./", p); 1945 if (cpy != NULL) 1946 { 1947 vim_free(p); 1948 p = cpy; 1949 } 1950 } 1951 else if (!is_relative_to_current) 1952 { 1953 // Strip leading "./". 1954 q = p; 1955 while (q[0] == '.' && vim_ispathsep(q[1])) 1956 q += 2; 1957 if (q > p) 1958 STRMOVE(p, p + 2); 1959 } 1960 } 1961 1962 // Ensure that the result will have no trailing path separator 1963 // if the argument had none. But keep "/" or "//". 1964 if (!has_trailing_pathsep) 1965 { 1966 q = p + STRLEN(p); 1967 if (after_pathsep(p, q)) 1968 *gettail_sep(p) = NUL; 1969 } 1970 1971 rettv->vval.v_string = p; 1972 } 1973 # else 1974 rettv->vval.v_string = vim_strsave(p); 1975 # endif 1976 #endif 1977 1978 simplify_filename(rettv->vval.v_string); 1979 1980 #ifdef HAVE_READLINK 1981 fail: 1982 vim_free(buf); 1983 #endif 1984 rettv->v_type = VAR_STRING; 1985 } 1986 1987 /* 1988 * "tempname()" function 1989 */ 1990 void 1991 f_tempname(typval_T *argvars UNUSED, typval_T *rettv) 1992 { 1993 static int x = 'A'; 1994 1995 rettv->v_type = VAR_STRING; 1996 rettv->vval.v_string = vim_tempname(x, FALSE); 1997 1998 // Advance 'x' to use A-Z and 0-9, so that there are at least 34 different 1999 // names. Skip 'I' and 'O', they are used for shell redirection. 2000 do 2001 { 2002 if (x == 'Z') 2003 x = '0'; 2004 else if (x == '9') 2005 x = 'A'; 2006 else 2007 { 2008 #ifdef EBCDIC 2009 if (x == 'I') 2010 x = 'J'; 2011 else if (x == 'R') 2012 x = 'S'; 2013 else 2014 #endif 2015 ++x; 2016 } 2017 } while (x == 'I' || x == 'O'); 2018 } 2019 2020 /* 2021 * "writefile()" function 2022 */ 2023 void 2024 f_writefile(typval_T *argvars, typval_T *rettv) 2025 { 2026 int binary = FALSE; 2027 int append = FALSE; 2028 #ifdef HAVE_FSYNC 2029 int do_fsync = p_fs; 2030 #endif 2031 char_u *fname; 2032 FILE *fd; 2033 int ret = 0; 2034 listitem_T *li; 2035 list_T *list = NULL; 2036 blob_T *blob = NULL; 2037 2038 rettv->vval.v_number = -1; 2039 if (check_secure()) 2040 return; 2041 2042 if (argvars[0].v_type == VAR_LIST) 2043 { 2044 list = argvars[0].vval.v_list; 2045 if (list == NULL) 2046 return; 2047 CHECK_LIST_MATERIALIZE(list); 2048 FOR_ALL_LIST_ITEMS(list, li) 2049 if (tv_get_string_chk(&li->li_tv) == NULL) 2050 return; 2051 } 2052 else if (argvars[0].v_type == VAR_BLOB) 2053 { 2054 blob = argvars[0].vval.v_blob; 2055 if (blob == NULL) 2056 return; 2057 } 2058 else 2059 { 2060 semsg(_(e_invarg2), 2061 _("writefile() first argument must be a List or a Blob")); 2062 return; 2063 } 2064 2065 if (argvars[2].v_type != VAR_UNKNOWN) 2066 { 2067 char_u *arg2 = tv_get_string_chk(&argvars[2]); 2068 2069 if (arg2 == NULL) 2070 return; 2071 if (vim_strchr(arg2, 'b') != NULL) 2072 binary = TRUE; 2073 if (vim_strchr(arg2, 'a') != NULL) 2074 append = TRUE; 2075 #ifdef HAVE_FSYNC 2076 if (vim_strchr(arg2, 's') != NULL) 2077 do_fsync = TRUE; 2078 else if (vim_strchr(arg2, 'S') != NULL) 2079 do_fsync = FALSE; 2080 #endif 2081 } 2082 2083 fname = tv_get_string_chk(&argvars[1]); 2084 if (fname == NULL) 2085 return; 2086 2087 // Always open the file in binary mode, library functions have a mind of 2088 // their own about CR-LF conversion. 2089 if (*fname == NUL || (fd = mch_fopen((char *)fname, 2090 append ? APPENDBIN : WRITEBIN)) == NULL) 2091 { 2092 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname); 2093 ret = -1; 2094 } 2095 else if (blob) 2096 { 2097 if (write_blob(fd, blob) == FAIL) 2098 ret = -1; 2099 #ifdef HAVE_FSYNC 2100 else if (do_fsync) 2101 // Ignore the error, the user wouldn't know what to do about it. 2102 // May happen for a device. 2103 vim_ignored = vim_fsync(fileno(fd)); 2104 #endif 2105 fclose(fd); 2106 } 2107 else 2108 { 2109 if (write_list(fd, list, binary) == FAIL) 2110 ret = -1; 2111 #ifdef HAVE_FSYNC 2112 else if (do_fsync) 2113 // Ignore the error, the user wouldn't know what to do about it. 2114 // May happen for a device. 2115 vim_ignored = vim_fsync(fileno(fd)); 2116 #endif 2117 fclose(fd); 2118 } 2119 2120 rettv->vval.v_number = ret; 2121 } 2122 2123 #endif // FEAT_EVAL 2124 2125 #if defined(FEAT_BROWSE) || defined(PROTO) 2126 /* 2127 * Generic browse function. Calls gui_mch_browse() when possible. 2128 * Later this may pop-up a non-GUI file selector (external command?). 2129 */ 2130 char_u * 2131 do_browse( 2132 int flags, // BROWSE_SAVE and BROWSE_DIR 2133 char_u *title, // title for the window 2134 char_u *dflt, // default file name (may include directory) 2135 char_u *ext, // extension added 2136 char_u *initdir, // initial directory, NULL for current dir or 2137 // when using path from "dflt" 2138 char_u *filter, // file name filter 2139 buf_T *buf) // buffer to read/write for 2140 { 2141 char_u *fname; 2142 static char_u *last_dir = NULL; // last used directory 2143 char_u *tofree = NULL; 2144 int save_browse = cmdmod.browse; 2145 2146 // Must turn off browse to avoid that autocommands will get the 2147 // flag too! 2148 cmdmod.browse = FALSE; 2149 2150 if (title == NULL || *title == NUL) 2151 { 2152 if (flags & BROWSE_DIR) 2153 title = (char_u *)_("Select Directory dialog"); 2154 else if (flags & BROWSE_SAVE) 2155 title = (char_u *)_("Save File dialog"); 2156 else 2157 title = (char_u *)_("Open File dialog"); 2158 } 2159 2160 // When no directory specified, use default file name, default dir, buffer 2161 // dir, last dir or current dir 2162 if ((initdir == NULL || *initdir == NUL) && dflt != NULL && *dflt != NUL) 2163 { 2164 if (mch_isdir(dflt)) // default file name is a directory 2165 { 2166 initdir = dflt; 2167 dflt = NULL; 2168 } 2169 else if (gettail(dflt) != dflt) // default file name includes a path 2170 { 2171 tofree = vim_strsave(dflt); 2172 if (tofree != NULL) 2173 { 2174 initdir = tofree; 2175 *gettail(initdir) = NUL; 2176 dflt = gettail(dflt); 2177 } 2178 } 2179 } 2180 2181 if (initdir == NULL || *initdir == NUL) 2182 { 2183 // When 'browsedir' is a directory, use it 2184 if (STRCMP(p_bsdir, "last") != 0 2185 && STRCMP(p_bsdir, "buffer") != 0 2186 && STRCMP(p_bsdir, "current") != 0 2187 && mch_isdir(p_bsdir)) 2188 initdir = p_bsdir; 2189 // When saving or 'browsedir' is "buffer", use buffer fname 2190 else if (((flags & BROWSE_SAVE) || *p_bsdir == 'b') 2191 && buf != NULL && buf->b_ffname != NULL) 2192 { 2193 if (dflt == NULL || *dflt == NUL) 2194 dflt = gettail(curbuf->b_ffname); 2195 tofree = vim_strsave(curbuf->b_ffname); 2196 if (tofree != NULL) 2197 { 2198 initdir = tofree; 2199 *gettail(initdir) = NUL; 2200 } 2201 } 2202 // When 'browsedir' is "last", use dir from last browse 2203 else if (*p_bsdir == 'l') 2204 initdir = last_dir; 2205 // When 'browsedir is "current", use current directory. This is the 2206 // default already, leave initdir empty. 2207 } 2208 2209 # ifdef FEAT_GUI 2210 if (gui.in_use) // when this changes, also adjust f_has()! 2211 { 2212 if (filter == NULL 2213 # ifdef FEAT_EVAL 2214 && (filter = get_var_value((char_u *)"b:browsefilter")) == NULL 2215 && (filter = get_var_value((char_u *)"g:browsefilter")) == NULL 2216 # endif 2217 ) 2218 filter = BROWSE_FILTER_DEFAULT; 2219 if (flags & BROWSE_DIR) 2220 { 2221 # if defined(FEAT_GUI_GTK) || defined(MSWIN) 2222 // For systems that have a directory dialog. 2223 fname = gui_mch_browsedir(title, initdir); 2224 # else 2225 // Generic solution for selecting a directory: select a file and 2226 // remove the file name. 2227 fname = gui_mch_browse(0, title, dflt, ext, initdir, (char_u *)""); 2228 # endif 2229 # if !defined(FEAT_GUI_GTK) 2230 // Win32 adds a dummy file name, others return an arbitrary file 2231 // name. GTK+ 2 returns only the directory, 2232 if (fname != NULL && *fname != NUL && !mch_isdir(fname)) 2233 { 2234 // Remove the file name. 2235 char_u *tail = gettail_sep(fname); 2236 2237 if (tail == fname) 2238 *tail++ = '.'; // use current dir 2239 *tail = NUL; 2240 } 2241 # endif 2242 } 2243 else 2244 fname = gui_mch_browse(flags & BROWSE_SAVE, 2245 title, dflt, ext, initdir, (char_u *)_(filter)); 2246 2247 // We hang around in the dialog for a while, the user might do some 2248 // things to our files. The Win32 dialog allows deleting or renaming 2249 // a file, check timestamps. 2250 need_check_timestamps = TRUE; 2251 did_check_timestamps = FALSE; 2252 } 2253 else 2254 # endif 2255 { 2256 // TODO: non-GUI file selector here 2257 emsg(_("E338: Sorry, no file browser in console mode")); 2258 fname = NULL; 2259 } 2260 2261 // keep the directory for next time 2262 if (fname != NULL) 2263 { 2264 vim_free(last_dir); 2265 last_dir = vim_strsave(fname); 2266 if (last_dir != NULL && !(flags & BROWSE_DIR)) 2267 { 2268 *gettail(last_dir) = NUL; 2269 if (*last_dir == NUL) 2270 { 2271 // filename only returned, must be in current dir 2272 vim_free(last_dir); 2273 last_dir = alloc(MAXPATHL); 2274 if (last_dir != NULL) 2275 mch_dirname(last_dir, MAXPATHL); 2276 } 2277 } 2278 } 2279 2280 vim_free(tofree); 2281 cmdmod.browse = save_browse; 2282 2283 return fname; 2284 } 2285 #endif 2286 2287 #if defined(FEAT_EVAL) || defined(PROTO) 2288 2289 /* 2290 * "browse(save, title, initdir, default)" function 2291 */ 2292 void 2293 f_browse(typval_T *argvars UNUSED, typval_T *rettv) 2294 { 2295 # ifdef FEAT_BROWSE 2296 int save; 2297 char_u *title; 2298 char_u *initdir; 2299 char_u *defname; 2300 char_u buf[NUMBUFLEN]; 2301 char_u buf2[NUMBUFLEN]; 2302 int error = FALSE; 2303 2304 save = (int)tv_get_number_chk(&argvars[0], &error); 2305 title = tv_get_string_chk(&argvars[1]); 2306 initdir = tv_get_string_buf_chk(&argvars[2], buf); 2307 defname = tv_get_string_buf_chk(&argvars[3], buf2); 2308 2309 if (error || title == NULL || initdir == NULL || defname == NULL) 2310 rettv->vval.v_string = NULL; 2311 else 2312 rettv->vval.v_string = 2313 do_browse(save ? BROWSE_SAVE : 0, 2314 title, defname, NULL, initdir, NULL, curbuf); 2315 # else 2316 rettv->vval.v_string = NULL; 2317 # endif 2318 rettv->v_type = VAR_STRING; 2319 } 2320 2321 /* 2322 * "browsedir(title, initdir)" function 2323 */ 2324 void 2325 f_browsedir(typval_T *argvars UNUSED, typval_T *rettv) 2326 { 2327 # ifdef FEAT_BROWSE 2328 char_u *title; 2329 char_u *initdir; 2330 char_u buf[NUMBUFLEN]; 2331 2332 title = tv_get_string_chk(&argvars[0]); 2333 initdir = tv_get_string_buf_chk(&argvars[1], buf); 2334 2335 if (title == NULL || initdir == NULL) 2336 rettv->vval.v_string = NULL; 2337 else 2338 rettv->vval.v_string = do_browse(BROWSE_DIR, 2339 title, NULL, NULL, initdir, NULL, curbuf); 2340 # else 2341 rettv->vval.v_string = NULL; 2342 # endif 2343 rettv->v_type = VAR_STRING; 2344 } 2345 2346 #endif // FEAT_EVAL 2347 2348 /* 2349 * Replace home directory by "~" in each space or comma separated file name in 2350 * 'src'. 2351 * If anything fails (except when out of space) dst equals src. 2352 */ 2353 void 2354 home_replace( 2355 buf_T *buf, // when not NULL, check for help files 2356 char_u *src, // input file name 2357 char_u *dst, // where to put the result 2358 int dstlen, // maximum length of the result 2359 int one) // if TRUE, only replace one file name, include 2360 // spaces and commas in the file name. 2361 { 2362 size_t dirlen = 0, envlen = 0; 2363 size_t len; 2364 char_u *homedir_env, *homedir_env_orig; 2365 char_u *p; 2366 2367 if (src == NULL) 2368 { 2369 *dst = NUL; 2370 return; 2371 } 2372 2373 /* 2374 * If the file is a help file, remove the path completely. 2375 */ 2376 if (buf != NULL && buf->b_help) 2377 { 2378 vim_snprintf((char *)dst, dstlen, "%s", gettail(src)); 2379 return; 2380 } 2381 2382 /* 2383 * We check both the value of the $HOME environment variable and the 2384 * "real" home directory. 2385 */ 2386 if (homedir != NULL) 2387 dirlen = STRLEN(homedir); 2388 2389 #ifdef VMS 2390 homedir_env_orig = homedir_env = mch_getenv((char_u *)"SYS$LOGIN"); 2391 #else 2392 homedir_env_orig = homedir_env = mch_getenv((char_u *)"HOME"); 2393 #endif 2394 #ifdef MSWIN 2395 if (homedir_env == NULL) 2396 homedir_env_orig = homedir_env = mch_getenv((char_u *)"USERPROFILE"); 2397 #endif 2398 // Empty is the same as not set. 2399 if (homedir_env != NULL && *homedir_env == NUL) 2400 homedir_env = NULL; 2401 2402 if (homedir_env != NULL && *homedir_env == '~') 2403 { 2404 int usedlen = 0; 2405 int flen; 2406 char_u *fbuf = NULL; 2407 2408 flen = (int)STRLEN(homedir_env); 2409 (void)modify_fname((char_u *)":p", FALSE, &usedlen, 2410 &homedir_env, &fbuf, &flen); 2411 flen = (int)STRLEN(homedir_env); 2412 if (flen > 0 && vim_ispathsep(homedir_env[flen - 1])) 2413 // Remove the trailing / that is added to a directory. 2414 homedir_env[flen - 1] = NUL; 2415 } 2416 2417 if (homedir_env != NULL) 2418 envlen = STRLEN(homedir_env); 2419 2420 if (!one) 2421 src = skipwhite(src); 2422 while (*src && dstlen > 0) 2423 { 2424 /* 2425 * Here we are at the beginning of a file name. 2426 * First, check to see if the beginning of the file name matches 2427 * $HOME or the "real" home directory. Check that there is a '/' 2428 * after the match (so that if e.g. the file is "/home/pieter/bla", 2429 * and the home directory is "/home/piet", the file does not end up 2430 * as "~er/bla" (which would seem to indicate the file "bla" in user 2431 * er's home directory)). 2432 */ 2433 p = homedir; 2434 len = dirlen; 2435 for (;;) 2436 { 2437 if ( len 2438 && fnamencmp(src, p, len) == 0 2439 && (vim_ispathsep(src[len]) 2440 || (!one && (src[len] == ',' || src[len] == ' ')) 2441 || src[len] == NUL)) 2442 { 2443 src += len; 2444 if (--dstlen > 0) 2445 *dst++ = '~'; 2446 2447 // Do not add directory separator into dst, because dst is 2448 // expected to just return the directory name without the 2449 // directory separator '/'. 2450 break; 2451 } 2452 if (p == homedir_env) 2453 break; 2454 p = homedir_env; 2455 len = envlen; 2456 } 2457 2458 // if (!one) skip to separator: space or comma 2459 while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0) 2460 *dst++ = *src++; 2461 // skip separator 2462 while ((*src == ' ' || *src == ',') && --dstlen > 0) 2463 *dst++ = *src++; 2464 } 2465 // if (dstlen == 0) out of space, what to do??? 2466 2467 *dst = NUL; 2468 2469 if (homedir_env != homedir_env_orig) 2470 vim_free(homedir_env); 2471 } 2472 2473 /* 2474 * Like home_replace, store the replaced string in allocated memory. 2475 * When something fails, NULL is returned. 2476 */ 2477 char_u * 2478 home_replace_save( 2479 buf_T *buf, // when not NULL, check for help files 2480 char_u *src) // input file name 2481 { 2482 char_u *dst; 2483 unsigned len; 2484 2485 len = 3; // space for "~/" and trailing NUL 2486 if (src != NULL) // just in case 2487 len += (unsigned)STRLEN(src); 2488 dst = alloc(len); 2489 if (dst != NULL) 2490 home_replace(buf, src, dst, len, TRUE); 2491 return dst; 2492 } 2493 2494 /* 2495 * Compare two file names and return: 2496 * FPC_SAME if they both exist and are the same file. 2497 * FPC_SAMEX if they both don't exist and have the same file name. 2498 * FPC_DIFF if they both exist and are different files. 2499 * FPC_NOTX if they both don't exist. 2500 * FPC_DIFFX if one of them doesn't exist. 2501 * For the first name environment variables are expanded if "expandenv" is 2502 * TRUE. 2503 */ 2504 int 2505 fullpathcmp( 2506 char_u *s1, 2507 char_u *s2, 2508 int checkname, // when both don't exist, check file names 2509 int expandenv) 2510 { 2511 #ifdef UNIX 2512 char_u exp1[MAXPATHL]; 2513 char_u full1[MAXPATHL]; 2514 char_u full2[MAXPATHL]; 2515 stat_T st1, st2; 2516 int r1, r2; 2517 2518 if (expandenv) 2519 expand_env(s1, exp1, MAXPATHL); 2520 else 2521 vim_strncpy(exp1, s1, MAXPATHL - 1); 2522 r1 = mch_stat((char *)exp1, &st1); 2523 r2 = mch_stat((char *)s2, &st2); 2524 if (r1 != 0 && r2 != 0) 2525 { 2526 // if mch_stat() doesn't work, may compare the names 2527 if (checkname) 2528 { 2529 if (fnamecmp(exp1, s2) == 0) 2530 return FPC_SAMEX; 2531 r1 = vim_FullName(exp1, full1, MAXPATHL, FALSE); 2532 r2 = vim_FullName(s2, full2, MAXPATHL, FALSE); 2533 if (r1 == OK && r2 == OK && fnamecmp(full1, full2) == 0) 2534 return FPC_SAMEX; 2535 } 2536 return FPC_NOTX; 2537 } 2538 if (r1 != 0 || r2 != 0) 2539 return FPC_DIFFX; 2540 if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) 2541 return FPC_SAME; 2542 return FPC_DIFF; 2543 #else 2544 char_u *exp1; // expanded s1 2545 char_u *full1; // full path of s1 2546 char_u *full2; // full path of s2 2547 int retval = FPC_DIFF; 2548 int r1, r2; 2549 2550 // allocate one buffer to store three paths (alloc()/free() is slow!) 2551 if ((exp1 = alloc(MAXPATHL * 3)) != NULL) 2552 { 2553 full1 = exp1 + MAXPATHL; 2554 full2 = full1 + MAXPATHL; 2555 2556 if (expandenv) 2557 expand_env(s1, exp1, MAXPATHL); 2558 else 2559 vim_strncpy(exp1, s1, MAXPATHL - 1); 2560 r1 = vim_FullName(exp1, full1, MAXPATHL, FALSE); 2561 r2 = vim_FullName(s2, full2, MAXPATHL, FALSE); 2562 2563 // If vim_FullName() fails, the file probably doesn't exist. 2564 if (r1 != OK && r2 != OK) 2565 { 2566 if (checkname && fnamecmp(exp1, s2) == 0) 2567 retval = FPC_SAMEX; 2568 else 2569 retval = FPC_NOTX; 2570 } 2571 else if (r1 != OK || r2 != OK) 2572 retval = FPC_DIFFX; 2573 else if (fnamecmp(full1, full2)) 2574 retval = FPC_DIFF; 2575 else 2576 retval = FPC_SAME; 2577 vim_free(exp1); 2578 } 2579 return retval; 2580 #endif 2581 } 2582 2583 /* 2584 * Get the tail of a path: the file name. 2585 * When the path ends in a path separator the tail is the NUL after it. 2586 * Fail safe: never returns NULL. 2587 */ 2588 char_u * 2589 gettail(char_u *fname) 2590 { 2591 char_u *p1, *p2; 2592 2593 if (fname == NULL) 2594 return (char_u *)""; 2595 for (p1 = p2 = get_past_head(fname); *p2; ) // find last part of path 2596 { 2597 if (vim_ispathsep_nocolon(*p2)) 2598 p1 = p2 + 1; 2599 MB_PTR_ADV(p2); 2600 } 2601 return p1; 2602 } 2603 2604 /* 2605 * Get pointer to tail of "fname", including path separators. Putting a NUL 2606 * here leaves the directory name. Takes care of "c:/" and "//". 2607 * Always returns a valid pointer. 2608 */ 2609 char_u * 2610 gettail_sep(char_u *fname) 2611 { 2612 char_u *p; 2613 char_u *t; 2614 2615 p = get_past_head(fname); // don't remove the '/' from "c:/file" 2616 t = gettail(fname); 2617 while (t > p && after_pathsep(fname, t)) 2618 --t; 2619 #ifdef VMS 2620 // path separator is part of the path 2621 ++t; 2622 #endif 2623 return t; 2624 } 2625 2626 /* 2627 * get the next path component (just after the next path separator). 2628 */ 2629 char_u * 2630 getnextcomp(char_u *fname) 2631 { 2632 while (*fname && !vim_ispathsep(*fname)) 2633 MB_PTR_ADV(fname); 2634 if (*fname) 2635 ++fname; 2636 return fname; 2637 } 2638 2639 /* 2640 * Get a pointer to one character past the head of a path name. 2641 * Unix: after "/"; DOS: after "c:\"; Amiga: after "disk:/"; Mac: no head. 2642 * If there is no head, path is returned. 2643 */ 2644 char_u * 2645 get_past_head(char_u *path) 2646 { 2647 char_u *retval; 2648 2649 #if defined(MSWIN) 2650 // may skip "c:" 2651 if (isalpha(path[0]) && path[1] == ':') 2652 retval = path + 2; 2653 else 2654 retval = path; 2655 #else 2656 # if defined(AMIGA) 2657 // may skip "label:" 2658 retval = vim_strchr(path, ':'); 2659 if (retval == NULL) 2660 retval = path; 2661 # else // Unix 2662 retval = path; 2663 # endif 2664 #endif 2665 2666 while (vim_ispathsep(*retval)) 2667 ++retval; 2668 2669 return retval; 2670 } 2671 2672 /* 2673 * Return TRUE if 'c' is a path separator. 2674 * Note that for MS-Windows this includes the colon. 2675 */ 2676 int 2677 vim_ispathsep(int c) 2678 { 2679 #ifdef UNIX 2680 return (c == '/'); // UNIX has ':' inside file names 2681 #else 2682 # ifdef BACKSLASH_IN_FILENAME 2683 return (c == ':' || c == '/' || c == '\\'); 2684 # else 2685 # ifdef VMS 2686 // server"user passwd"::device:[full.path.name]fname.extension;version" 2687 return (c == ':' || c == '[' || c == ']' || c == '/' 2688 || c == '<' || c == '>' || c == '"' ); 2689 # else 2690 return (c == ':' || c == '/'); 2691 # endif // VMS 2692 # endif 2693 #endif 2694 } 2695 2696 /* 2697 * Like vim_ispathsep(c), but exclude the colon for MS-Windows. 2698 */ 2699 int 2700 vim_ispathsep_nocolon(int c) 2701 { 2702 return vim_ispathsep(c) 2703 #ifdef BACKSLASH_IN_FILENAME 2704 && c != ':' 2705 #endif 2706 ; 2707 } 2708 2709 /* 2710 * Shorten the path of a file from "~/foo/../.bar/fname" to "~/f/../.b/fname" 2711 * It's done in-place. 2712 */ 2713 void 2714 shorten_dir(char_u *str) 2715 { 2716 char_u *tail, *s, *d; 2717 int skip = FALSE; 2718 2719 tail = gettail(str); 2720 d = str; 2721 for (s = str; ; ++s) 2722 { 2723 if (s >= tail) // copy the whole tail 2724 { 2725 *d++ = *s; 2726 if (*s == NUL) 2727 break; 2728 } 2729 else if (vim_ispathsep(*s)) // copy '/' and next char 2730 { 2731 *d++ = *s; 2732 skip = FALSE; 2733 } 2734 else if (!skip) 2735 { 2736 *d++ = *s; // copy next char 2737 if (*s != '~' && *s != '.') // and leading "~" and "." 2738 skip = TRUE; 2739 if (has_mbyte) 2740 { 2741 int l = mb_ptr2len(s); 2742 2743 while (--l > 0) 2744 *d++ = *++s; 2745 } 2746 } 2747 } 2748 } 2749 2750 /* 2751 * Return TRUE if the directory of "fname" exists, FALSE otherwise. 2752 * Also returns TRUE if there is no directory name. 2753 * "fname" must be writable!. 2754 */ 2755 int 2756 dir_of_file_exists(char_u *fname) 2757 { 2758 char_u *p; 2759 int c; 2760 int retval; 2761 2762 p = gettail_sep(fname); 2763 if (p == fname) 2764 return TRUE; 2765 c = *p; 2766 *p = NUL; 2767 retval = mch_isdir(fname); 2768 *p = c; 2769 return retval; 2770 } 2771 2772 /* 2773 * Versions of fnamecmp() and fnamencmp() that handle '/' and '\' equally 2774 * and deal with 'fileignorecase'. 2775 */ 2776 int 2777 vim_fnamecmp(char_u *x, char_u *y) 2778 { 2779 #ifdef BACKSLASH_IN_FILENAME 2780 return vim_fnamencmp(x, y, MAXPATHL); 2781 #else 2782 if (p_fic) 2783 return MB_STRICMP(x, y); 2784 return STRCMP(x, y); 2785 #endif 2786 } 2787 2788 int 2789 vim_fnamencmp(char_u *x, char_u *y, size_t len) 2790 { 2791 #ifdef BACKSLASH_IN_FILENAME 2792 char_u *px = x; 2793 char_u *py = y; 2794 int cx = NUL; 2795 int cy = NUL; 2796 2797 while (len > 0) 2798 { 2799 cx = PTR2CHAR(px); 2800 cy = PTR2CHAR(py); 2801 if (cx == NUL || cy == NUL 2802 || ((p_fic ? MB_TOLOWER(cx) != MB_TOLOWER(cy) : cx != cy) 2803 && !(cx == '/' && cy == '\\') 2804 && !(cx == '\\' && cy == '/'))) 2805 break; 2806 len -= mb_ptr2len(px); 2807 px += mb_ptr2len(px); 2808 py += mb_ptr2len(py); 2809 } 2810 if (len == 0) 2811 return 0; 2812 return (cx - cy); 2813 #else 2814 if (p_fic) 2815 return MB_STRNICMP(x, y, len); 2816 return STRNCMP(x, y, len); 2817 #endif 2818 } 2819 2820 /* 2821 * Concatenate file names fname1 and fname2 into allocated memory. 2822 * Only add a '/' or '\\' when 'sep' is TRUE and it is necessary. 2823 */ 2824 char_u * 2825 concat_fnames(char_u *fname1, char_u *fname2, int sep) 2826 { 2827 char_u *dest; 2828 2829 dest = alloc(STRLEN(fname1) + STRLEN(fname2) + 3); 2830 if (dest != NULL) 2831 { 2832 STRCPY(dest, fname1); 2833 if (sep) 2834 add_pathsep(dest); 2835 STRCAT(dest, fname2); 2836 } 2837 return dest; 2838 } 2839 2840 /* 2841 * Add a path separator to a file name, unless it already ends in a path 2842 * separator. 2843 */ 2844 void 2845 add_pathsep(char_u *p) 2846 { 2847 if (*p != NUL && !after_pathsep(p, p + STRLEN(p))) 2848 STRCAT(p, PATHSEPSTR); 2849 } 2850 2851 /* 2852 * FullName_save - Make an allocated copy of a full file name. 2853 * Returns NULL when out of memory. 2854 */ 2855 char_u * 2856 FullName_save( 2857 char_u *fname, 2858 int force) // force expansion, even when it already looks 2859 // like a full path name 2860 { 2861 char_u *buf; 2862 char_u *new_fname = NULL; 2863 2864 if (fname == NULL) 2865 return NULL; 2866 2867 buf = alloc(MAXPATHL); 2868 if (buf != NULL) 2869 { 2870 if (vim_FullName(fname, buf, MAXPATHL, force) != FAIL) 2871 new_fname = vim_strsave(buf); 2872 else 2873 new_fname = vim_strsave(fname); 2874 vim_free(buf); 2875 } 2876 return new_fname; 2877 } 2878 2879 /* 2880 * return TRUE if "fname" exists. 2881 */ 2882 int 2883 vim_fexists(char_u *fname) 2884 { 2885 stat_T st; 2886 2887 if (mch_stat((char *)fname, &st)) 2888 return FALSE; 2889 return TRUE; 2890 } 2891 2892 /* 2893 * Invoke expand_wildcards() for one pattern. 2894 * Expand items like "%:h" before the expansion. 2895 * Returns OK or FAIL. 2896 */ 2897 int 2898 expand_wildcards_eval( 2899 char_u **pat, // pointer to input pattern 2900 int *num_file, // resulting number of files 2901 char_u ***file, // array of resulting files 2902 int flags) // EW_DIR, etc. 2903 { 2904 int ret = FAIL; 2905 char_u *eval_pat = NULL; 2906 char_u *exp_pat = *pat; 2907 char *ignored_msg; 2908 int usedlen; 2909 2910 if (*exp_pat == '%' || *exp_pat == '#' || *exp_pat == '<') 2911 { 2912 ++emsg_off; 2913 eval_pat = eval_vars(exp_pat, exp_pat, &usedlen, 2914 NULL, &ignored_msg, NULL); 2915 --emsg_off; 2916 if (eval_pat != NULL) 2917 exp_pat = concat_str(eval_pat, exp_pat + usedlen); 2918 } 2919 2920 if (exp_pat != NULL) 2921 ret = expand_wildcards(1, &exp_pat, num_file, file, flags); 2922 2923 if (eval_pat != NULL) 2924 { 2925 vim_free(exp_pat); 2926 vim_free(eval_pat); 2927 } 2928 2929 return ret; 2930 } 2931 2932 /* 2933 * Expand wildcards. Calls gen_expand_wildcards() and removes files matching 2934 * 'wildignore'. 2935 * Returns OK or FAIL. When FAIL then "num_files" won't be set. 2936 */ 2937 int 2938 expand_wildcards( 2939 int num_pat, // number of input patterns 2940 char_u **pat, // array of input patterns 2941 int *num_files, // resulting number of files 2942 char_u ***files, // array of resulting files 2943 int flags) // EW_DIR, etc. 2944 { 2945 int retval; 2946 int i, j; 2947 char_u *p; 2948 int non_suf_match; // number without matching suffix 2949 2950 retval = gen_expand_wildcards(num_pat, pat, num_files, files, flags); 2951 2952 // When keeping all matches, return here 2953 if ((flags & EW_KEEPALL) || retval == FAIL) 2954 return retval; 2955 2956 #ifdef FEAT_WILDIGN 2957 /* 2958 * Remove names that match 'wildignore'. 2959 */ 2960 if (*p_wig) 2961 { 2962 char_u *ffname; 2963 2964 // check all files in (*files)[] 2965 for (i = 0; i < *num_files; ++i) 2966 { 2967 ffname = FullName_save((*files)[i], FALSE); 2968 if (ffname == NULL) // out of memory 2969 break; 2970 # ifdef VMS 2971 vms_remove_version(ffname); 2972 # endif 2973 if (match_file_list(p_wig, (*files)[i], ffname)) 2974 { 2975 // remove this matching file from the list 2976 vim_free((*files)[i]); 2977 for (j = i; j + 1 < *num_files; ++j) 2978 (*files)[j] = (*files)[j + 1]; 2979 --*num_files; 2980 --i; 2981 } 2982 vim_free(ffname); 2983 } 2984 2985 // If the number of matches is now zero, we fail. 2986 if (*num_files == 0) 2987 { 2988 VIM_CLEAR(*files); 2989 return FAIL; 2990 } 2991 } 2992 #endif 2993 2994 /* 2995 * Move the names where 'suffixes' match to the end. 2996 */ 2997 if (*num_files > 1) 2998 { 2999 non_suf_match = 0; 3000 for (i = 0; i < *num_files; ++i) 3001 { 3002 if (!match_suffix((*files)[i])) 3003 { 3004 /* 3005 * Move the name without matching suffix to the front 3006 * of the list. 3007 */ 3008 p = (*files)[i]; 3009 for (j = i; j > non_suf_match; --j) 3010 (*files)[j] = (*files)[j - 1]; 3011 (*files)[non_suf_match++] = p; 3012 } 3013 } 3014 } 3015 3016 return retval; 3017 } 3018 3019 /* 3020 * Return TRUE if "fname" matches with an entry in 'suffixes'. 3021 */ 3022 int 3023 match_suffix(char_u *fname) 3024 { 3025 int fnamelen, setsuflen; 3026 char_u *setsuf; 3027 #define MAXSUFLEN 30 // maximum length of a file suffix 3028 char_u suf_buf[MAXSUFLEN]; 3029 3030 fnamelen = (int)STRLEN(fname); 3031 setsuflen = 0; 3032 for (setsuf = p_su; *setsuf; ) 3033 { 3034 setsuflen = copy_option_part(&setsuf, suf_buf, MAXSUFLEN, ".,"); 3035 if (setsuflen == 0) 3036 { 3037 char_u *tail = gettail(fname); 3038 3039 // empty entry: match name without a '.' 3040 if (vim_strchr(tail, '.') == NULL) 3041 { 3042 setsuflen = 1; 3043 break; 3044 } 3045 } 3046 else 3047 { 3048 if (fnamelen >= setsuflen 3049 && fnamencmp(suf_buf, fname + fnamelen - setsuflen, 3050 (size_t)setsuflen) == 0) 3051 break; 3052 setsuflen = 0; 3053 } 3054 } 3055 return (setsuflen != 0); 3056 } 3057 3058 #ifdef VIM_BACKTICK 3059 3060 /* 3061 * Return TRUE if we can expand this backtick thing here. 3062 */ 3063 static int 3064 vim_backtick(char_u *p) 3065 { 3066 return (*p == '`' && *(p + 1) != NUL && *(p + STRLEN(p) - 1) == '`'); 3067 } 3068 3069 /* 3070 * Expand an item in `backticks` by executing it as a command. 3071 * Currently only works when pat[] starts and ends with a `. 3072 * Returns number of file names found, -1 if an error is encountered. 3073 */ 3074 static int 3075 expand_backtick( 3076 garray_T *gap, 3077 char_u *pat, 3078 int flags) // EW_* flags 3079 { 3080 char_u *p; 3081 char_u *cmd; 3082 char_u *buffer; 3083 int cnt = 0; 3084 int i; 3085 3086 // Create the command: lop off the backticks. 3087 cmd = vim_strnsave(pat + 1, STRLEN(pat) - 2); 3088 if (cmd == NULL) 3089 return -1; 3090 3091 #ifdef FEAT_EVAL 3092 if (*cmd == '=') // `={expr}`: Expand expression 3093 buffer = eval_to_string(cmd + 1, TRUE); 3094 else 3095 #endif 3096 buffer = get_cmd_output(cmd, NULL, 3097 (flags & EW_SILENT) ? SHELL_SILENT : 0, NULL); 3098 vim_free(cmd); 3099 if (buffer == NULL) 3100 return -1; 3101 3102 cmd = buffer; 3103 while (*cmd != NUL) 3104 { 3105 cmd = skipwhite(cmd); // skip over white space 3106 p = cmd; 3107 while (*p != NUL && *p != '\r' && *p != '\n') // skip over entry 3108 ++p; 3109 // add an entry if it is not empty 3110 if (p > cmd) 3111 { 3112 i = *p; 3113 *p = NUL; 3114 addfile(gap, cmd, flags); 3115 *p = i; 3116 ++cnt; 3117 } 3118 cmd = p; 3119 while (*cmd != NUL && (*cmd == '\r' || *cmd == '\n')) 3120 ++cmd; 3121 } 3122 3123 vim_free(buffer); 3124 return cnt; 3125 } 3126 #endif // VIM_BACKTICK 3127 3128 #if defined(MSWIN) 3129 /* 3130 * File name expansion code for MS-DOS, Win16 and Win32. It's here because 3131 * it's shared between these systems. 3132 */ 3133 3134 /* 3135 * comparison function for qsort in dos_expandpath() 3136 */ 3137 static int 3138 pstrcmp(const void *a, const void *b) 3139 { 3140 return (pathcmp(*(char **)a, *(char **)b, -1)); 3141 } 3142 3143 /* 3144 * Recursively expand one path component into all matching files and/or 3145 * directories. Adds matches to "gap". Handles "*", "?", "[a-z]", "**", etc. 3146 * Return the number of matches found. 3147 * "path" has backslashes before chars that are not to be expanded, starting 3148 * at "path[wildoff]". 3149 * Return the number of matches found. 3150 * NOTE: much of this is identical to unix_expandpath(), keep in sync! 3151 */ 3152 static int 3153 dos_expandpath( 3154 garray_T *gap, 3155 char_u *path, 3156 int wildoff, 3157 int flags, // EW_* flags 3158 int didstar) // expanded "**" once already 3159 { 3160 char_u *buf; 3161 char_u *path_end; 3162 char_u *p, *s, *e; 3163 int start_len = gap->ga_len; 3164 char_u *pat; 3165 regmatch_T regmatch; 3166 int starts_with_dot; 3167 int matches; 3168 int len; 3169 int starstar = FALSE; 3170 static int stardepth = 0; // depth for "**" expansion 3171 HANDLE hFind = INVALID_HANDLE_VALUE; 3172 WIN32_FIND_DATAW wfb; 3173 WCHAR *wn = NULL; // UCS-2 name, NULL when not used. 3174 char_u *matchname; 3175 int ok; 3176 char_u *p_alt; 3177 3178 // Expanding "**" may take a long time, check for CTRL-C. 3179 if (stardepth > 0) 3180 { 3181 ui_breakcheck(); 3182 if (got_int) 3183 return 0; 3184 } 3185 3186 // Make room for file name. When doing encoding conversion the actual 3187 // length may be quite a bit longer, thus use the maximum possible length. 3188 buf = alloc(MAXPATHL); 3189 if (buf == NULL) 3190 return 0; 3191 3192 /* 3193 * Find the first part in the path name that contains a wildcard or a ~1. 3194 * Copy it into buf, including the preceding characters. 3195 */ 3196 p = buf; 3197 s = buf; 3198 e = NULL; 3199 path_end = path; 3200 while (*path_end != NUL) 3201 { 3202 // May ignore a wildcard that has a backslash before it; it will 3203 // be removed by rem_backslash() or file_pat_to_reg_pat() below. 3204 if (path_end >= path + wildoff && rem_backslash(path_end)) 3205 *p++ = *path_end++; 3206 else if (*path_end == '\\' || *path_end == ':' || *path_end == '/') 3207 { 3208 if (e != NULL) 3209 break; 3210 s = p + 1; 3211 } 3212 else if (path_end >= path + wildoff 3213 && vim_strchr((char_u *)"*?[~", *path_end) != NULL) 3214 e = p; 3215 if (has_mbyte) 3216 { 3217 len = (*mb_ptr2len)(path_end); 3218 STRNCPY(p, path_end, len); 3219 p += len; 3220 path_end += len; 3221 } 3222 else 3223 *p++ = *path_end++; 3224 } 3225 e = p; 3226 *e = NUL; 3227 3228 // now we have one wildcard component between s and e 3229 // Remove backslashes between "wildoff" and the start of the wildcard 3230 // component. 3231 for (p = buf + wildoff; p < s; ++p) 3232 if (rem_backslash(p)) 3233 { 3234 STRMOVE(p, p + 1); 3235 --e; 3236 --s; 3237 } 3238 3239 // Check for "**" between "s" and "e". 3240 for (p = s; p < e; ++p) 3241 if (p[0] == '*' && p[1] == '*') 3242 starstar = TRUE; 3243 3244 starts_with_dot = *s == '.'; 3245 pat = file_pat_to_reg_pat(s, e, NULL, FALSE); 3246 if (pat == NULL) 3247 { 3248 vim_free(buf); 3249 return 0; 3250 } 3251 3252 // compile the regexp into a program 3253 if (flags & (EW_NOERROR | EW_NOTWILD)) 3254 ++emsg_silent; 3255 regmatch.rm_ic = TRUE; // Always ignore case 3256 regmatch.regprog = vim_regcomp(pat, RE_MAGIC); 3257 if (flags & (EW_NOERROR | EW_NOTWILD)) 3258 --emsg_silent; 3259 vim_free(pat); 3260 3261 if (regmatch.regprog == NULL && (flags & EW_NOTWILD) == 0) 3262 { 3263 vim_free(buf); 3264 return 0; 3265 } 3266 3267 // remember the pattern or file name being looked for 3268 matchname = vim_strsave(s); 3269 3270 // If "**" is by itself, this is the first time we encounter it and more 3271 // is following then find matches without any directory. 3272 if (!didstar && stardepth < 100 && starstar && e - s == 2 3273 && *path_end == '/') 3274 { 3275 STRCPY(s, path_end + 1); 3276 ++stardepth; 3277 (void)dos_expandpath(gap, buf, (int)(s - buf), flags, TRUE); 3278 --stardepth; 3279 } 3280 3281 // Scan all files in the directory with "dir/ *.*" 3282 STRCPY(s, "*.*"); 3283 wn = enc_to_utf16(buf, NULL); 3284 if (wn != NULL) 3285 hFind = FindFirstFileW(wn, &wfb); 3286 ok = (hFind != INVALID_HANDLE_VALUE); 3287 3288 while (ok) 3289 { 3290 p = utf16_to_enc(wfb.cFileName, NULL); // p is allocated here 3291 3292 if (p == NULL) 3293 break; // out of memory 3294 3295 if (*wfb.cAlternateFileName == NUL) 3296 p_alt = NULL; 3297 else 3298 p_alt = utf16_to_enc(wfb.cAlternateFileName, NULL); 3299 3300 // Ignore entries starting with a dot, unless when asked for. Accept 3301 // all entries found with "matchname". 3302 if ((p[0] != '.' || starts_with_dot 3303 || ((flags & EW_DODOT) 3304 && p[1] != NUL && (p[1] != '.' || p[2] != NUL))) 3305 && (matchname == NULL 3306 || (regmatch.regprog != NULL 3307 && (vim_regexec(®match, p, (colnr_T)0) 3308 || (p_alt != NULL 3309 && vim_regexec(®match, p_alt, (colnr_T)0)))) 3310 || ((flags & EW_NOTWILD) 3311 && fnamencmp(path + (s - buf), p, e - s) == 0))) 3312 { 3313 STRCPY(s, p); 3314 len = (int)STRLEN(buf); 3315 3316 if (starstar && stardepth < 100 3317 && (wfb.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 3318 { 3319 // For "**" in the pattern first go deeper in the tree to 3320 // find matches. 3321 STRCPY(buf + len, "/**"); 3322 STRCPY(buf + len + 3, path_end); 3323 ++stardepth; 3324 (void)dos_expandpath(gap, buf, len + 1, flags, TRUE); 3325 --stardepth; 3326 } 3327 3328 STRCPY(buf + len, path_end); 3329 if (mch_has_exp_wildcard(path_end)) 3330 { 3331 // need to expand another component of the path 3332 // remove backslashes for the remaining components only 3333 (void)dos_expandpath(gap, buf, len + 1, flags, FALSE); 3334 } 3335 else 3336 { 3337 // no more wildcards, check if there is a match 3338 // remove backslashes for the remaining components only 3339 if (*path_end != 0) 3340 backslash_halve(buf + len + 1); 3341 if (mch_getperm(buf) >= 0) // add existing file 3342 addfile(gap, buf, flags); 3343 } 3344 } 3345 3346 vim_free(p_alt); 3347 vim_free(p); 3348 ok = FindNextFileW(hFind, &wfb); 3349 } 3350 3351 FindClose(hFind); 3352 vim_free(wn); 3353 vim_free(buf); 3354 vim_regfree(regmatch.regprog); 3355 vim_free(matchname); 3356 3357 matches = gap->ga_len - start_len; 3358 if (matches > 0) 3359 qsort(((char_u **)gap->ga_data) + start_len, (size_t)matches, 3360 sizeof(char_u *), pstrcmp); 3361 return matches; 3362 } 3363 3364 int 3365 mch_expandpath( 3366 garray_T *gap, 3367 char_u *path, 3368 int flags) // EW_* flags 3369 { 3370 return dos_expandpath(gap, path, 0, flags, FALSE); 3371 } 3372 #endif // MSWIN 3373 3374 #if (defined(UNIX) && !defined(VMS)) || defined(USE_UNIXFILENAME) \ 3375 || defined(PROTO) 3376 /* 3377 * Unix style wildcard expansion code. 3378 * It's here because it's used both for Unix and Mac. 3379 */ 3380 static int 3381 pstrcmp(const void *a, const void *b) 3382 { 3383 return (pathcmp(*(char **)a, *(char **)b, -1)); 3384 } 3385 3386 /* 3387 * Recursively expand one path component into all matching files and/or 3388 * directories. Adds matches to "gap". Handles "*", "?", "[a-z]", "**", etc. 3389 * "path" has backslashes before chars that are not to be expanded, starting 3390 * at "path + wildoff". 3391 * Return the number of matches found. 3392 * NOTE: much of this is identical to dos_expandpath(), keep in sync! 3393 */ 3394 int 3395 unix_expandpath( 3396 garray_T *gap, 3397 char_u *path, 3398 int wildoff, 3399 int flags, // EW_* flags 3400 int didstar) // expanded "**" once already 3401 { 3402 char_u *buf; 3403 char_u *path_end; 3404 char_u *p, *s, *e; 3405 int start_len = gap->ga_len; 3406 char_u *pat; 3407 regmatch_T regmatch; 3408 int starts_with_dot; 3409 int matches; 3410 int len; 3411 int starstar = FALSE; 3412 static int stardepth = 0; // depth for "**" expansion 3413 3414 DIR *dirp; 3415 struct dirent *dp; 3416 3417 // Expanding "**" may take a long time, check for CTRL-C. 3418 if (stardepth > 0) 3419 { 3420 ui_breakcheck(); 3421 if (got_int) 3422 return 0; 3423 } 3424 3425 // make room for file name 3426 buf = alloc(STRLEN(path) + BASENAMELEN + 5); 3427 if (buf == NULL) 3428 return 0; 3429 3430 /* 3431 * Find the first part in the path name that contains a wildcard. 3432 * When EW_ICASE is set every letter is considered to be a wildcard. 3433 * Copy it into "buf", including the preceding characters. 3434 */ 3435 p = buf; 3436 s = buf; 3437 e = NULL; 3438 path_end = path; 3439 while (*path_end != NUL) 3440 { 3441 // May ignore a wildcard that has a backslash before it; it will 3442 // be removed by rem_backslash() or file_pat_to_reg_pat() below. 3443 if (path_end >= path + wildoff && rem_backslash(path_end)) 3444 *p++ = *path_end++; 3445 else if (*path_end == '/') 3446 { 3447 if (e != NULL) 3448 break; 3449 s = p + 1; 3450 } 3451 else if (path_end >= path + wildoff 3452 && (vim_strchr((char_u *)"*?[{~$", *path_end) != NULL 3453 || (!p_fic && (flags & EW_ICASE) 3454 && isalpha(PTR2CHAR(path_end))))) 3455 e = p; 3456 if (has_mbyte) 3457 { 3458 len = (*mb_ptr2len)(path_end); 3459 STRNCPY(p, path_end, len); 3460 p += len; 3461 path_end += len; 3462 } 3463 else 3464 *p++ = *path_end++; 3465 } 3466 e = p; 3467 *e = NUL; 3468 3469 // Now we have one wildcard component between "s" and "e". 3470 // Remove backslashes between "wildoff" and the start of the wildcard 3471 // component. 3472 for (p = buf + wildoff; p < s; ++p) 3473 if (rem_backslash(p)) 3474 { 3475 STRMOVE(p, p + 1); 3476 --e; 3477 --s; 3478 } 3479 3480 // Check for "**" between "s" and "e". 3481 for (p = s; p < e; ++p) 3482 if (p[0] == '*' && p[1] == '*') 3483 starstar = TRUE; 3484 3485 // convert the file pattern to a regexp pattern 3486 starts_with_dot = *s == '.'; 3487 pat = file_pat_to_reg_pat(s, e, NULL, FALSE); 3488 if (pat == NULL) 3489 { 3490 vim_free(buf); 3491 return 0; 3492 } 3493 3494 // compile the regexp into a program 3495 if (flags & EW_ICASE) 3496 regmatch.rm_ic = TRUE; // 'wildignorecase' set 3497 else 3498 regmatch.rm_ic = p_fic; // ignore case when 'fileignorecase' is set 3499 if (flags & (EW_NOERROR | EW_NOTWILD)) 3500 ++emsg_silent; 3501 regmatch.regprog = vim_regcomp(pat, RE_MAGIC); 3502 if (flags & (EW_NOERROR | EW_NOTWILD)) 3503 --emsg_silent; 3504 vim_free(pat); 3505 3506 if (regmatch.regprog == NULL && (flags & EW_NOTWILD) == 0) 3507 { 3508 vim_free(buf); 3509 return 0; 3510 } 3511 3512 // If "**" is by itself, this is the first time we encounter it and more 3513 // is following then find matches without any directory. 3514 if (!didstar && stardepth < 100 && starstar && e - s == 2 3515 && *path_end == '/') 3516 { 3517 STRCPY(s, path_end + 1); 3518 ++stardepth; 3519 (void)unix_expandpath(gap, buf, (int)(s - buf), flags, TRUE); 3520 --stardepth; 3521 } 3522 3523 // open the directory for scanning 3524 *s = NUL; 3525 dirp = opendir(*buf == NUL ? "." : (char *)buf); 3526 3527 // Find all matching entries 3528 if (dirp != NULL) 3529 { 3530 for (;;) 3531 { 3532 dp = readdir(dirp); 3533 if (dp == NULL) 3534 break; 3535 if ((dp->d_name[0] != '.' || starts_with_dot 3536 || ((flags & EW_DODOT) 3537 && dp->d_name[1] != NUL 3538 && (dp->d_name[1] != '.' || dp->d_name[2] != NUL))) 3539 && ((regmatch.regprog != NULL && vim_regexec(®match, 3540 (char_u *)dp->d_name, (colnr_T)0)) 3541 || ((flags & EW_NOTWILD) 3542 && fnamencmp(path + (s - buf), dp->d_name, e - s) == 0))) 3543 { 3544 STRCPY(s, dp->d_name); 3545 len = STRLEN(buf); 3546 3547 if (starstar && stardepth < 100) 3548 { 3549 // For "**" in the pattern first go deeper in the tree to 3550 // find matches. 3551 STRCPY(buf + len, "/**"); 3552 STRCPY(buf + len + 3, path_end); 3553 ++stardepth; 3554 (void)unix_expandpath(gap, buf, len + 1, flags, TRUE); 3555 --stardepth; 3556 } 3557 3558 STRCPY(buf + len, path_end); 3559 if (mch_has_exp_wildcard(path_end)) // handle more wildcards 3560 { 3561 // need to expand another component of the path 3562 // remove backslashes for the remaining components only 3563 (void)unix_expandpath(gap, buf, len + 1, flags, FALSE); 3564 } 3565 else 3566 { 3567 stat_T sb; 3568 3569 // no more wildcards, check if there is a match 3570 // remove backslashes for the remaining components only 3571 if (*path_end != NUL) 3572 backslash_halve(buf + len + 1); 3573 // add existing file or symbolic link 3574 if ((flags & EW_ALLLINKS) ? mch_lstat((char *)buf, &sb) >= 0 3575 : mch_getperm(buf) >= 0) 3576 { 3577 #ifdef MACOS_CONVERT 3578 size_t precomp_len = STRLEN(buf)+1; 3579 char_u *precomp_buf = 3580 mac_precompose_path(buf, precomp_len, &precomp_len); 3581 3582 if (precomp_buf) 3583 { 3584 mch_memmove(buf, precomp_buf, precomp_len); 3585 vim_free(precomp_buf); 3586 } 3587 #endif 3588 addfile(gap, buf, flags); 3589 } 3590 } 3591 } 3592 } 3593 3594 closedir(dirp); 3595 } 3596 3597 vim_free(buf); 3598 vim_regfree(regmatch.regprog); 3599 3600 matches = gap->ga_len - start_len; 3601 if (matches > 0) 3602 qsort(((char_u **)gap->ga_data) + start_len, matches, 3603 sizeof(char_u *), pstrcmp); 3604 return matches; 3605 } 3606 #endif 3607 3608 /* 3609 * Return TRUE if "p" contains what looks like an environment variable. 3610 * Allowing for escaping. 3611 */ 3612 static int 3613 has_env_var(char_u *p) 3614 { 3615 for ( ; *p; MB_PTR_ADV(p)) 3616 { 3617 if (*p == '\\' && p[1] != NUL) 3618 ++p; 3619 else if (vim_strchr((char_u *) 3620 #if defined(MSWIN) 3621 "$%" 3622 #else 3623 "$" 3624 #endif 3625 , *p) != NULL) 3626 return TRUE; 3627 } 3628 return FALSE; 3629 } 3630 3631 #ifdef SPECIAL_WILDCHAR 3632 /* 3633 * Return TRUE if "p" contains a special wildcard character, one that Vim 3634 * cannot expand, requires using a shell. 3635 */ 3636 static int 3637 has_special_wildchar(char_u *p) 3638 { 3639 for ( ; *p; MB_PTR_ADV(p)) 3640 { 3641 // Disallow line break characters. 3642 if (*p == '\r' || *p == '\n') 3643 break; 3644 // Allow for escaping. 3645 if (*p == '\\' && p[1] != NUL && p[1] != '\r' && p[1] != '\n') 3646 ++p; 3647 else if (vim_strchr((char_u *)SPECIAL_WILDCHAR, *p) != NULL) 3648 { 3649 // A { must be followed by a matching }. 3650 if (*p == '{' && vim_strchr(p, '}') == NULL) 3651 continue; 3652 // A quote and backtick must be followed by another one. 3653 if ((*p == '`' || *p == '\'') && vim_strchr(p, *p) == NULL) 3654 continue; 3655 return TRUE; 3656 } 3657 } 3658 return FALSE; 3659 } 3660 #endif 3661 3662 /* 3663 * Generic wildcard expansion code. 3664 * 3665 * Characters in "pat" that should not be expanded must be preceded with a 3666 * backslash. E.g., "/path\ with\ spaces/my\*star*" 3667 * 3668 * Return FAIL when no single file was found. In this case "num_file" is not 3669 * set, and "file" may contain an error message. 3670 * Return OK when some files found. "num_file" is set to the number of 3671 * matches, "file" to the array of matches. Call FreeWild() later. 3672 */ 3673 int 3674 gen_expand_wildcards( 3675 int num_pat, // number of input patterns 3676 char_u **pat, // array of input patterns 3677 int *num_file, // resulting number of files 3678 char_u ***file, // array of resulting files 3679 int flags) // EW_* flags 3680 { 3681 int i; 3682 garray_T ga; 3683 char_u *p; 3684 static int recursive = FALSE; 3685 int add_pat; 3686 int retval = OK; 3687 #if defined(FEAT_SEARCHPATH) 3688 int did_expand_in_path = FALSE; 3689 #endif 3690 3691 /* 3692 * expand_env() is called to expand things like "~user". If this fails, 3693 * it calls ExpandOne(), which brings us back here. In this case, always 3694 * call the machine specific expansion function, if possible. Otherwise, 3695 * return FAIL. 3696 */ 3697 if (recursive) 3698 #ifdef SPECIAL_WILDCHAR 3699 return mch_expand_wildcards(num_pat, pat, num_file, file, flags); 3700 #else 3701 return FAIL; 3702 #endif 3703 3704 #ifdef SPECIAL_WILDCHAR 3705 /* 3706 * If there are any special wildcard characters which we cannot handle 3707 * here, call machine specific function for all the expansion. This 3708 * avoids starting the shell for each argument separately. 3709 * For `=expr` do use the internal function. 3710 */ 3711 for (i = 0; i < num_pat; i++) 3712 { 3713 if (has_special_wildchar(pat[i]) 3714 # ifdef VIM_BACKTICK 3715 && !(vim_backtick(pat[i]) && pat[i][1] == '=') 3716 # endif 3717 ) 3718 return mch_expand_wildcards(num_pat, pat, num_file, file, flags); 3719 } 3720 #endif 3721 3722 recursive = TRUE; 3723 3724 /* 3725 * The matching file names are stored in a growarray. Init it empty. 3726 */ 3727 ga_init2(&ga, (int)sizeof(char_u *), 30); 3728 3729 for (i = 0; i < num_pat; ++i) 3730 { 3731 add_pat = -1; 3732 p = pat[i]; 3733 3734 #ifdef VIM_BACKTICK 3735 if (vim_backtick(p)) 3736 { 3737 add_pat = expand_backtick(&ga, p, flags); 3738 if (add_pat == -1) 3739 retval = FAIL; 3740 } 3741 else 3742 #endif 3743 { 3744 /* 3745 * First expand environment variables, "~/" and "~user/". 3746 */ 3747 if ((has_env_var(p) && !(flags & EW_NOTENV)) || *p == '~') 3748 { 3749 p = expand_env_save_opt(p, TRUE); 3750 if (p == NULL) 3751 p = pat[i]; 3752 #ifdef UNIX 3753 /* 3754 * On Unix, if expand_env() can't expand an environment 3755 * variable, use the shell to do that. Discard previously 3756 * found file names and start all over again. 3757 */ 3758 else if (has_env_var(p) || *p == '~') 3759 { 3760 vim_free(p); 3761 ga_clear_strings(&ga); 3762 i = mch_expand_wildcards(num_pat, pat, num_file, file, 3763 flags|EW_KEEPDOLLAR); 3764 recursive = FALSE; 3765 return i; 3766 } 3767 #endif 3768 } 3769 3770 /* 3771 * If there are wildcards: Expand file names and add each match to 3772 * the list. If there is no match, and EW_NOTFOUND is given, add 3773 * the pattern. 3774 * If there are no wildcards: Add the file name if it exists or 3775 * when EW_NOTFOUND is given. 3776 */ 3777 if (mch_has_exp_wildcard(p)) 3778 { 3779 #if defined(FEAT_SEARCHPATH) 3780 if ((flags & EW_PATH) 3781 && !mch_isFullName(p) 3782 && !(p[0] == '.' 3783 && (vim_ispathsep(p[1]) 3784 || (p[1] == '.' && vim_ispathsep(p[2])))) 3785 ) 3786 { 3787 // :find completion where 'path' is used. 3788 // Recursiveness is OK here. 3789 recursive = FALSE; 3790 add_pat = expand_in_path(&ga, p, flags); 3791 recursive = TRUE; 3792 did_expand_in_path = TRUE; 3793 } 3794 else 3795 #endif 3796 add_pat = mch_expandpath(&ga, p, flags); 3797 } 3798 } 3799 3800 if (add_pat == -1 || (add_pat == 0 && (flags & EW_NOTFOUND))) 3801 { 3802 char_u *t = backslash_halve_save(p); 3803 3804 // When EW_NOTFOUND is used, always add files and dirs. Makes 3805 // "vim c:/" work. 3806 if (flags & EW_NOTFOUND) 3807 addfile(&ga, t, flags | EW_DIR | EW_FILE); 3808 else 3809 addfile(&ga, t, flags); 3810 3811 if (t != p) 3812 vim_free(t); 3813 } 3814 3815 #if defined(FEAT_SEARCHPATH) 3816 if (did_expand_in_path && ga.ga_len > 0 && (flags & EW_PATH)) 3817 uniquefy_paths(&ga, p); 3818 #endif 3819 if (p != pat[i]) 3820 vim_free(p); 3821 } 3822 3823 // When returning FAIL the array must be freed here. 3824 if (retval == FAIL) 3825 ga_clear(&ga); 3826 3827 *num_file = ga.ga_len; 3828 *file = (ga.ga_data != NULL) ? (char_u **)ga.ga_data 3829 : (char_u **)_("no matches"); 3830 3831 recursive = FALSE; 3832 3833 return ((flags & EW_EMPTYOK) || ga.ga_data != NULL) ? retval : FAIL; 3834 } 3835 3836 /* 3837 * Add a file to a file list. Accepted flags: 3838 * EW_DIR add directories 3839 * EW_FILE add files 3840 * EW_EXEC add executable files 3841 * EW_NOTFOUND add even when it doesn't exist 3842 * EW_ADDSLASH add slash after directory name 3843 * EW_ALLLINKS add symlink also when the referred file does not exist 3844 */ 3845 void 3846 addfile( 3847 garray_T *gap, 3848 char_u *f, // filename 3849 int flags) 3850 { 3851 char_u *p; 3852 int isdir; 3853 stat_T sb; 3854 3855 // if the file/dir/link doesn't exist, may not add it 3856 if (!(flags & EW_NOTFOUND) && ((flags & EW_ALLLINKS) 3857 ? mch_lstat((char *)f, &sb) < 0 : mch_getperm(f) < 0)) 3858 return; 3859 3860 #ifdef FNAME_ILLEGAL 3861 // if the file/dir contains illegal characters, don't add it 3862 if (vim_strpbrk(f, (char_u *)FNAME_ILLEGAL) != NULL) 3863 return; 3864 #endif 3865 3866 isdir = mch_isdir(f); 3867 if ((isdir && !(flags & EW_DIR)) || (!isdir && !(flags & EW_FILE))) 3868 return; 3869 3870 // If the file isn't executable, may not add it. Do accept directories. 3871 // When invoked from expand_shellcmd() do not use $PATH. 3872 if (!isdir && (flags & EW_EXEC) 3873 && !mch_can_exe(f, NULL, !(flags & EW_SHELLCMD))) 3874 return; 3875 3876 // Make room for another item in the file list. 3877 if (ga_grow(gap, 1) == FAIL) 3878 return; 3879 3880 p = alloc(STRLEN(f) + 1 + isdir); 3881 if (p == NULL) 3882 return; 3883 3884 STRCPY(p, f); 3885 #ifdef BACKSLASH_IN_FILENAME 3886 slash_adjust(p); 3887 #endif 3888 /* 3889 * Append a slash or backslash after directory names if none is present. 3890 */ 3891 #ifndef DONT_ADD_PATHSEP_TO_DIR 3892 if (isdir && (flags & EW_ADDSLASH)) 3893 add_pathsep(p); 3894 #endif 3895 ((char_u **)gap->ga_data)[gap->ga_len++] = p; 3896 } 3897 3898 /* 3899 * Free the list of files returned by expand_wildcards() or other expansion 3900 * functions. 3901 */ 3902 void 3903 FreeWild(int count, char_u **files) 3904 { 3905 if (count <= 0 || files == NULL) 3906 return; 3907 while (count--) 3908 vim_free(files[count]); 3909 vim_free(files); 3910 } 3911 3912 /* 3913 * Compare path "p[]" to "q[]". 3914 * If "maxlen" >= 0 compare "p[maxlen]" to "q[maxlen]" 3915 * Return value like strcmp(p, q), but consider path separators. 3916 */ 3917 int 3918 pathcmp(const char *p, const char *q, int maxlen) 3919 { 3920 int i, j; 3921 int c1, c2; 3922 const char *s = NULL; 3923 3924 for (i = 0, j = 0; maxlen < 0 || (i < maxlen && j < maxlen);) 3925 { 3926 c1 = PTR2CHAR((char_u *)p + i); 3927 c2 = PTR2CHAR((char_u *)q + j); 3928 3929 // End of "p": check if "q" also ends or just has a slash. 3930 if (c1 == NUL) 3931 { 3932 if (c2 == NUL) // full match 3933 return 0; 3934 s = q; 3935 i = j; 3936 break; 3937 } 3938 3939 // End of "q": check if "p" just has a slash. 3940 if (c2 == NUL) 3941 { 3942 s = p; 3943 break; 3944 } 3945 3946 if ((p_fic ? MB_TOUPPER(c1) != MB_TOUPPER(c2) : c1 != c2) 3947 #ifdef BACKSLASH_IN_FILENAME 3948 // consider '/' and '\\' to be equal 3949 && !((c1 == '/' && c2 == '\\') 3950 || (c1 == '\\' && c2 == '/')) 3951 #endif 3952 ) 3953 { 3954 if (vim_ispathsep(c1)) 3955 return -1; 3956 if (vim_ispathsep(c2)) 3957 return 1; 3958 return p_fic ? MB_TOUPPER(c1) - MB_TOUPPER(c2) 3959 : c1 - c2; // no match 3960 } 3961 3962 i += mb_ptr2len((char_u *)p + i); 3963 j += mb_ptr2len((char_u *)q + j); 3964 } 3965 if (s == NULL) // "i" or "j" ran into "maxlen" 3966 return 0; 3967 3968 c1 = PTR2CHAR((char_u *)s + i); 3969 c2 = PTR2CHAR((char_u *)s + i + mb_ptr2len((char_u *)s + i)); 3970 // ignore a trailing slash, but not "//" or ":/" 3971 if (c2 == NUL 3972 && i > 0 3973 && !after_pathsep((char_u *)s, (char_u *)s + i) 3974 #ifdef BACKSLASH_IN_FILENAME 3975 && (c1 == '/' || c1 == '\\') 3976 #else 3977 && c1 == '/' 3978 #endif 3979 ) 3980 return 0; // match with trailing slash 3981 if (s == q) 3982 return -1; // no match 3983 return 1; 3984 } 3985 3986 /* 3987 * Return TRUE if "name" is a full (absolute) path name or URL. 3988 */ 3989 int 3990 vim_isAbsName(char_u *name) 3991 { 3992 return (path_with_url(name) != 0 || mch_isFullName(name)); 3993 } 3994 3995 /* 3996 * Get absolute file name into buffer "buf[len]". 3997 * 3998 * return FAIL for failure, OK otherwise 3999 */ 4000 int 4001 vim_FullName( 4002 char_u *fname, 4003 char_u *buf, 4004 int len, 4005 int force) // force expansion even when already absolute 4006 { 4007 int retval = OK; 4008 int url; 4009 4010 *buf = NUL; 4011 if (fname == NULL) 4012 return FAIL; 4013 4014 url = path_with_url(fname); 4015 if (!url) 4016 retval = mch_FullName(fname, buf, len, force); 4017 if (url || retval == FAIL) 4018 { 4019 // something failed; use the file name (truncate when too long) 4020 vim_strncpy(buf, fname, len - 1); 4021 } 4022 #if defined(MSWIN) 4023 slash_adjust(buf); 4024 #endif 4025 return retval; 4026 } 4027