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