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