diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileio.c | 647 |
1 files changed, 414 insertions, 233 deletions
diff --git a/src/fileio.c b/src/fileio.c index 7493a29f1a4..d01b70c7af7 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* File IO for GNU Emacs. | 1 | /* File IO for GNU Emacs. |
| 2 | Copyright (C) 1985, 86, 87, 88, 93, 94, 95 Free Software Foundation, Inc. | 2 | Copyright (C) 1985,86,87,88,93,94,95,96 Free Software Foundation, Inc. |
| 3 | 3 | ||
| 4 | This file is part of GNU Emacs. | 4 | This file is part of GNU Emacs. |
| 5 | 5 | ||
| @@ -93,6 +93,21 @@ extern char *strerror (); | |||
| 93 | #include <fcntl.h> | 93 | #include <fcntl.h> |
| 94 | #endif /* not WINDOWSNT */ | 94 | #endif /* not WINDOWSNT */ |
| 95 | 95 | ||
| 96 | #ifdef DOS_NT | ||
| 97 | #define CORRECT_DIR_SEPS(s) \ | ||
| 98 | do { if ('/' == DIRECTORY_SEP) dostounix_filename (s); \ | ||
| 99 | else unixtodos_filename (s); \ | ||
| 100 | } while (0) | ||
| 101 | /* On Windows, drive letters must be alphabetic - on DOS, the Netware | ||
| 102 | redirector allows the six letters between 'Z' and 'a' as well. */ | ||
| 103 | #ifdef MSDOS | ||
| 104 | #define IS_DRIVE(x) ((x) >= 'A' && (x) <= 'z') | ||
| 105 | #endif | ||
| 106 | #ifdef WINDOWSNT | ||
| 107 | #define IS_DRIVE(x) isalpha (x) | ||
| 108 | #endif | ||
| 109 | #endif | ||
| 110 | |||
| 96 | #ifdef VMS | 111 | #ifdef VMS |
| 97 | #include <file.h> | 112 | #include <file.h> |
| 98 | #include <rmsdef.h> | 113 | #include <rmsdef.h> |
| @@ -129,7 +144,7 @@ int auto_saving; | |||
| 129 | a new file with the same mode as the original */ | 144 | a new file with the same mode as the original */ |
| 130 | int auto_save_mode_bits; | 145 | int auto_save_mode_bits; |
| 131 | 146 | ||
| 132 | /* Alist of elements (REGEXP . HANDLER) for file names | 147 | /* Alist of elements (REGEXP . HANDLER) for file names |
| 133 | whose I/O is done with a special handler. */ | 148 | whose I/O is done with a special handler. */ |
| 134 | Lisp_Object Vfile_name_handler_alist; | 149 | Lisp_Object Vfile_name_handler_alist; |
| 135 | 150 | ||
| @@ -160,6 +175,10 @@ int insert_default_directory; | |||
| 160 | Zero means use var format. */ | 175 | Zero means use var format. */ |
| 161 | int vms_stmlf_recfm; | 176 | int vms_stmlf_recfm; |
| 162 | 177 | ||
| 178 | /* On NT, specifies the directory separator character, used (eg.) when | ||
| 179 | expanding file names. This can be bound to / or \. */ | ||
| 180 | Lisp_Object Vdirectory_sep_char; | ||
| 181 | |||
| 163 | /* These variables describe handlers that have "already" had a chance | 182 | /* These variables describe handlers that have "already" had a chance |
| 164 | to handle the current operation. | 183 | to handle the current operation. |
| 165 | 184 | ||
| @@ -203,7 +222,7 @@ close_file_unwind (fd) | |||
| 203 | /* Restore point, having saved it as a marker. */ | 222 | /* Restore point, having saved it as a marker. */ |
| 204 | 223 | ||
| 205 | restore_point_unwind (location) | 224 | restore_point_unwind (location) |
| 206 | Lisp_Object location; | 225 | Lisp_Object location; |
| 207 | { | 226 | { |
| 208 | SET_PT (marker_position (location)); | 227 | SET_PT (marker_position (location)); |
| 209 | Fset_marker (location, Qnil, Qnil); | 228 | Fset_marker (location, Qnil, Qnil); |
| @@ -312,44 +331,38 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.") | |||
| 312 | filename = FILE_SYSTEM_CASE (filename); | 331 | filename = FILE_SYSTEM_CASE (filename); |
| 313 | #endif | 332 | #endif |
| 314 | beg = XSTRING (filename)->data; | 333 | beg = XSTRING (filename)->data; |
| 334 | #ifdef DOS_NT | ||
| 335 | beg = strcpy (alloca (strlen (beg) + 1), beg); | ||
| 336 | #endif | ||
| 315 | p = beg + XSTRING (filename)->size; | 337 | p = beg + XSTRING (filename)->size; |
| 316 | 338 | ||
| 317 | while (p != beg && !IS_ANY_SEP (p[-1]) | 339 | while (p != beg && !IS_DIRECTORY_SEP (p[-1]) |
| 318 | #ifdef VMS | 340 | #ifdef VMS |
| 319 | && p[-1] != ':' && p[-1] != ']' && p[-1] != '>' | 341 | && p[-1] != ':' && p[-1] != ']' && p[-1] != '>' |
| 320 | #endif /* VMS */ | 342 | #endif /* VMS */ |
| 343 | #ifdef DOS_NT | ||
| 344 | /* only recognise drive specifier at beginning */ | ||
| 345 | && !(p[-1] == ':' && p == beg + 2) | ||
| 346 | #endif | ||
| 321 | ) p--; | 347 | ) p--; |
| 322 | 348 | ||
| 323 | if (p == beg) | 349 | if (p == beg) |
| 324 | return Qnil; | 350 | return Qnil; |
| 325 | #ifdef DOS_NT | 351 | #ifdef DOS_NT |
| 326 | /* Expansion of "c:" to drive and default directory. */ | 352 | /* Expansion of "c:" to drive and default directory. */ |
| 327 | /* (NT does the right thing.) */ | ||
| 328 | if (p == beg + 2 && beg[1] == ':') | 353 | if (p == beg + 2 && beg[1] == ':') |
| 329 | { | 354 | { |
| 330 | int drive = (*beg) - 'a'; | ||
| 331 | /* MAXPATHLEN+1 is guaranteed to be enough space for getdefdir. */ | 355 | /* MAXPATHLEN+1 is guaranteed to be enough space for getdefdir. */ |
| 332 | unsigned char *res = alloca (MAXPATHLEN + 5); | 356 | unsigned char *res = alloca (MAXPATHLEN + 1); |
| 333 | unsigned char *res1; | 357 | if (getdefdir (toupper (*beg) - 'A' + 1, res)) |
| 334 | #ifdef WINDOWSNT | ||
| 335 | res1 = res; | ||
| 336 | /* The NT version places the drive letter at the beginning already. */ | ||
| 337 | #else /* not WINDOWSNT */ | ||
| 338 | /* On MSDOG we must put the drive letter in by hand. */ | ||
| 339 | res1 = res + 2; | ||
| 340 | #endif /* not WINDOWSNT */ | ||
| 341 | if (getdefdir (drive + 1, res)) | ||
| 342 | { | 358 | { |
| 343 | #ifdef MSDOS | 359 | if (!IS_DIRECTORY_SEP (res[strlen (res) - 1])) |
| 344 | res[0] = drive + 'a'; | ||
| 345 | res[1] = ':'; | ||
| 346 | #endif /* MSDOS */ | ||
| 347 | if (IS_DIRECTORY_SEP (res[strlen (res) - 1])) | ||
| 348 | strcat (res, "/"); | 360 | strcat (res, "/"); |
| 349 | beg = res; | 361 | beg = res; |
| 350 | p = beg + strlen (beg); | 362 | p = beg + strlen (beg); |
| 351 | } | 363 | } |
| 352 | } | 364 | } |
| 365 | CORRECT_DIR_SEPS (beg); | ||
| 353 | #endif /* DOS_NT */ | 366 | #endif /* DOS_NT */ |
| 354 | return make_string (beg, p - beg); | 367 | return make_string (beg, p - beg); |
| 355 | } | 368 | } |
| @@ -377,10 +390,14 @@ or the entire name if it contains no slash.") | |||
| 377 | beg = XSTRING (filename)->data; | 390 | beg = XSTRING (filename)->data; |
| 378 | end = p = beg + XSTRING (filename)->size; | 391 | end = p = beg + XSTRING (filename)->size; |
| 379 | 392 | ||
| 380 | while (p != beg && !IS_ANY_SEP (p[-1]) | 393 | while (p != beg && !IS_DIRECTORY_SEP (p[-1]) |
| 381 | #ifdef VMS | 394 | #ifdef VMS |
| 382 | && p[-1] != ':' && p[-1] != ']' && p[-1] != '>' | 395 | && p[-1] != ':' && p[-1] != ']' && p[-1] != '>' |
| 383 | #endif /* VMS */ | 396 | #endif /* VMS */ |
| 397 | #ifdef DOS_NT | ||
| 398 | /* only recognise drive specifier at beginning */ | ||
| 399 | && !(p[-1] == ':' && p == beg + 2) | ||
| 400 | #endif | ||
| 384 | ) p--; | 401 | ) p--; |
| 385 | 402 | ||
| 386 | return make_string (p, end - p); | 403 | return make_string (p, end - p); |
| @@ -476,11 +493,14 @@ file_name_as_directory (out, in) | |||
| 476 | } | 493 | } |
| 477 | #else /* not VMS */ | 494 | #else /* not VMS */ |
| 478 | /* For Unix syntax, Append a slash if necessary */ | 495 | /* For Unix syntax, Append a slash if necessary */ |
| 479 | if (!IS_ANY_SEP (out[size])) | 496 | if (!IS_DIRECTORY_SEP (out[size])) |
| 480 | { | 497 | { |
| 481 | out[size + 1] = DIRECTORY_SEP; | 498 | out[size + 1] = DIRECTORY_SEP; |
| 482 | out[size + 2] = '\0'; | 499 | out[size + 2] = '\0'; |
| 483 | } | 500 | } |
| 501 | #ifdef DOS_NT | ||
| 502 | CORRECT_DIR_SEPS (out); | ||
| 503 | #endif | ||
| 484 | #endif /* not VMS */ | 504 | #endif /* not VMS */ |
| 485 | return out; | 505 | return out; |
| 486 | } | 506 | } |
| @@ -519,7 +539,7 @@ On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.") | |||
| 519 | * On VMS: | 539 | * On VMS: |
| 520 | * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1 | 540 | * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1 |
| 521 | * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1 | 541 | * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1 |
| 522 | * On UNIX, it's simple: just make sure there is a terminating / | 542 | * On UNIX, it's simple: just make sure there isn't a terminating / |
| 523 | 543 | ||
| 524 | * Value is nonzero if the string output is different from the input. | 544 | * Value is nonzero if the string output is different from the input. |
| 525 | */ | 545 | */ |
| @@ -555,7 +575,7 @@ directory_file_name (src, dst) | |||
| 555 | nam.nam$b_nop |= NAM$M_SYNCHK; | 575 | nam.nam$b_nop |= NAM$M_SYNCHK; |
| 556 | 576 | ||
| 557 | /* We call SYS$PARSE to handle such things as [--] for us. */ | 577 | /* We call SYS$PARSE to handle such things as [--] for us. */ |
| 558 | if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL) | 578 | if (SYS$PARSE (&fab, 0, 0) == RMS$_NORMAL) |
| 559 | { | 579 | { |
| 560 | slen = nam.nam$b_esl; | 580 | slen = nam.nam$b_esl; |
| 561 | if (esa[slen - 1] == ';' && esa[slen - 2] == '.') | 581 | if (esa[slen - 1] == ';' && esa[slen - 2] == '.') |
| @@ -624,7 +644,7 @@ directory_file_name (src, dst) | |||
| 624 | then translate the device and recurse. */ | 644 | then translate the device and recurse. */ |
| 625 | if (dst[slen - 1] == ':' | 645 | if (dst[slen - 1] == ':' |
| 626 | && dst[slen - 2] != ':' /* skip decnet nodes */ | 646 | && dst[slen - 2] != ':' /* skip decnet nodes */ |
| 627 | && strcmp(src + slen, "[000000]") == 0) | 647 | && strcmp (src + slen, "[000000]") == 0) |
| 628 | { | 648 | { |
| 629 | dst[slen - 1] = '\0'; | 649 | dst[slen - 1] = '\0'; |
| 630 | if ((ptr = egetenv (dst)) | 650 | if ((ptr = egetenv (dst)) |
| @@ -661,7 +681,7 @@ directory_file_name (src, dst) | |||
| 661 | || (slen > 1 && dst[0] != '/' && dst[slen - 1] == '/')) | 681 | || (slen > 1 && dst[0] != '/' && dst[slen - 1] == '/')) |
| 662 | dst[slen - 1] = 0; | 682 | dst[slen - 1] = 0; |
| 663 | #else | 683 | #else |
| 664 | if (slen > 1 | 684 | if (slen > 1 |
| 665 | && IS_DIRECTORY_SEP (dst[slen - 1]) | 685 | && IS_DIRECTORY_SEP (dst[slen - 1]) |
| 666 | #ifdef DOS_NT | 686 | #ifdef DOS_NT |
| 667 | && !IS_ANY_SEP (dst[slen - 2]) | 687 | && !IS_ANY_SEP (dst[slen - 2]) |
| @@ -669,6 +689,9 @@ directory_file_name (src, dst) | |||
| 669 | ) | 689 | ) |
| 670 | dst[slen - 1] = 0; | 690 | dst[slen - 1] = 0; |
| 671 | #endif | 691 | #endif |
| 692 | #ifdef DOS_NT | ||
| 693 | CORRECT_DIR_SEPS (dst); | ||
| 694 | #endif | ||
| 672 | return 1; | 695 | return 1; |
| 673 | } | 696 | } |
| 674 | 697 | ||
| @@ -726,6 +749,9 @@ so there is no danger of generating a name being used by another process.") | |||
| 726 | val = concat2 (prefix, build_string ("XXXXXX")); | 749 | val = concat2 (prefix, build_string ("XXXXXX")); |
| 727 | #endif | 750 | #endif |
| 728 | mktemp (XSTRING (val)->data); | 751 | mktemp (XSTRING (val)->data); |
| 752 | #ifdef DOS_NT | ||
| 753 | CORRECT_DIR_SEPS (XSTRING (val)->data); | ||
| 754 | #endif | ||
| 729 | return val; | 755 | return val; |
| 730 | } | 756 | } |
| 731 | 757 | ||
| @@ -734,10 +760,10 @@ DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0, | |||
| 734 | Second arg DEFAULT-DIRECTORY is directory to start with if NAME is relative\n\ | 760 | Second arg DEFAULT-DIRECTORY is directory to start with if NAME is relative\n\ |
| 735 | (does not start with slash); if DEFAULT-DIRECTORY is nil or missing,\n\ | 761 | (does not start with slash); if DEFAULT-DIRECTORY is nil or missing,\n\ |
| 736 | the current buffer's value of default-directory is used.\n\ | 762 | the current buffer's value of default-directory is used.\n\ |
| 737 | Path components that are `.' are removed, and \n\ | 763 | File name components that are `.' are removed, and \n\ |
| 738 | path components followed by `..' are removed, along with the `..' itself;\n\ | 764 | so are file name components followed by `..', along with the `..' itself;\n\ |
| 739 | note that these simplifications are done without checking the resulting\n\ | 765 | note that these simplifications are done without checking the resulting\n\ |
| 740 | paths in the file system.\n\ | 766 | file names in the file system.\n\ |
| 741 | An initial `~/' expands to your home directory.\n\ | 767 | An initial `~/' expands to your home directory.\n\ |
| 742 | An initial `~USER/' expands to USER's home directory.\n\ | 768 | An initial `~USER/' expands to USER's home directory.\n\ |
| 743 | See also the function `substitute-in-file-name'.") | 769 | See also the function `substitute-in-file-name'.") |
| @@ -745,7 +771,7 @@ See also the function `substitute-in-file-name'.") | |||
| 745 | Lisp_Object name, default_directory; | 771 | Lisp_Object name, default_directory; |
| 746 | { | 772 | { |
| 747 | unsigned char *nm; | 773 | unsigned char *nm; |
| 748 | 774 | ||
| 749 | register unsigned char *newdir, *p, *o; | 775 | register unsigned char *newdir, *p, *o; |
| 750 | int tlen; | 776 | int tlen; |
| 751 | unsigned char *target; | 777 | unsigned char *target; |
| @@ -759,13 +785,11 @@ See also the function `substitute-in-file-name'.") | |||
| 759 | int dots = 0; | 785 | int dots = 0; |
| 760 | #endif /* VMS */ | 786 | #endif /* VMS */ |
| 761 | #ifdef DOS_NT | 787 | #ifdef DOS_NT |
| 762 | /* Demacs 1.1.2 91/10/20 Manabu Higashida */ | 788 | int drive = 0; |
| 763 | int drive = -1; | ||
| 764 | int relpath = 0; | ||
| 765 | unsigned char *tmp, *defdir; | ||
| 766 | #endif /* DOS_NT */ | 789 | #endif /* DOS_NT */ |
| 790 | int length; | ||
| 767 | Lisp_Object handler; | 791 | Lisp_Object handler; |
| 768 | 792 | ||
| 769 | CHECK_STRING (name, 0); | 793 | CHECK_STRING (name, 0); |
| 770 | 794 | ||
| 771 | /* If the file name has special constructs in it, | 795 | /* If the file name has special constructs in it, |
| @@ -799,15 +823,22 @@ See also the function `substitute-in-file-name'.") | |||
| 799 | 823 | ||
| 800 | The EQ test avoids infinite recursion. */ | 824 | The EQ test avoids infinite recursion. */ |
| 801 | if (! NILP (default_directory) && !EQ (default_directory, name) | 825 | if (! NILP (default_directory) && !EQ (default_directory, name) |
| 802 | /* Save time in some common cases. */ | 826 | /* Save time in some common cases - as long as default_directory |
| 827 | is not relative, it can be canonicalized with name below (if it | ||
| 828 | is needed at all) without requiring it to be expanded now. */ | ||
| 803 | #ifdef DOS_NT | 829 | #ifdef DOS_NT |
| 804 | /* Detect MSDOS file names with device names. */ | 830 | /* Detect MSDOS file names with drive specifiers. */ |
| 805 | && ! (XSTRING (default_directory)->size >= 3 | 831 | && ! (IS_DRIVE (o[0]) && (IS_DEVICE_SEP (o[1]) && IS_DIRECTORY_SEP (o[2]))) |
| 806 | && IS_DEVICE_SEP (o[1]) && IS_DIRECTORY_SEP (o[2])) | 832 | #ifdef WINDOWSNT |
| 833 | /* Detect Windows file names in UNC format. */ | ||
| 834 | && ! (IS_DIRECTORY_SEP (o[0]) && IS_DIRECTORY_SEP (o[1])) | ||
| 807 | #endif | 835 | #endif |
| 808 | /* Detect Unix absolute file names. */ | 836 | #else /* not DOS_NT */ |
| 809 | && ! (XSTRING (default_directory)->size >= 2 | 837 | /* Detect Unix absolute file names (/... alone is not absolute on |
| 810 | && IS_DIRECTORY_SEP (o[0]))) | 838 | DOS or Windows). */ |
| 839 | && ! (IS_DIRECTORY_SEP (o[0])) | ||
| 840 | #endif /* not DOS_NT */ | ||
| 841 | ) | ||
| 811 | { | 842 | { |
| 812 | struct gcpro gcpro1; | 843 | struct gcpro gcpro1; |
| 813 | 844 | ||
| @@ -825,29 +856,38 @@ See also the function `substitute-in-file-name'.") | |||
| 825 | #endif | 856 | #endif |
| 826 | 857 | ||
| 827 | nm = XSTRING (name)->data; | 858 | nm = XSTRING (name)->data; |
| 828 | |||
| 829 | #ifdef MSDOS | ||
| 830 | /* First map all backslashes to slashes. */ | ||
| 831 | dostounix_filename (nm = strcpy (alloca (strlen (nm) + 1), nm)); | ||
| 832 | #endif | ||
| 833 | 859 | ||
| 834 | #ifdef DOS_NT | 860 | #ifdef DOS_NT |
| 835 | /* Now strip drive name. */ | 861 | /* We will force directory separators to be either all \ or /, so make |
| 862 | a local copy to modify, even if there ends up being no change. */ | ||
| 863 | nm = strcpy (alloca (strlen (nm) + 1), nm); | ||
| 864 | |||
| 865 | /* Find and remove drive specifier if present; this makes nm absolute | ||
| 866 | even if the rest of the name appears to be relative. */ | ||
| 836 | { | 867 | { |
| 837 | unsigned char *colon = rindex (nm, ':'); | 868 | unsigned char *colon = rindex (nm, ':'); |
| 869 | |||
| 838 | if (colon) | 870 | if (colon) |
| 871 | /* Only recognize colon as part of drive specifier if there is a | ||
| 872 | single alphabetic character preceeding the colon (and if the | ||
| 873 | character before the drive letter, if present, is a directory | ||
| 874 | separator); this is to support the remote system syntax used by | ||
| 875 | ange-ftp, and the "po:username" syntax for POP mailboxes. */ | ||
| 876 | look_again: | ||
| 839 | if (nm == colon) | 877 | if (nm == colon) |
| 840 | nm++; | 878 | nm++; |
| 841 | else | 879 | else if (IS_DRIVE (colon[-1]) |
| 880 | && (colon == nm + 1 || IS_DIRECTORY_SEP (colon[-2]))) | ||
| 842 | { | 881 | { |
| 843 | drive = colon[-1]; | 882 | drive = colon[-1]; |
| 844 | nm = colon + 1; | 883 | nm = colon + 1; |
| 845 | if (!IS_DIRECTORY_SEP (*nm)) | 884 | } |
| 846 | { | 885 | else |
| 847 | defdir = alloca (MAXPATHLEN + 1); | 886 | { |
| 848 | relpath = getdefdir (tolower (drive) - 'a' + 1, defdir); | 887 | while (--colon >= nm) |
| 849 | } | 888 | if (colon[0] == ':') |
| 850 | } | 889 | goto look_again; |
| 890 | } | ||
| 851 | } | 891 | } |
| 852 | #endif /* DOS_NT */ | 892 | #endif /* DOS_NT */ |
| 853 | 893 | ||
| @@ -856,31 +896,43 @@ See also the function `substitute-in-file-name'.") | |||
| 856 | p = nm; | 896 | p = nm; |
| 857 | while (*p) | 897 | while (*p) |
| 858 | { | 898 | { |
| 859 | /* Since we know the path is absolute, we can assume that each | 899 | /* Since we are expecting the name to be absolute, we can assume |
| 860 | element starts with a "/". */ | 900 | that each element starts with a "/". */ |
| 861 | 901 | ||
| 862 | /* "//" anywhere isn't necessarily hairy; we just start afresh | ||
| 863 | with the second slash. */ | ||
| 864 | if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1]) | 902 | if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1]) |
| 865 | #if defined (APOLLO) || defined (WINDOWSNT) | 903 | #if defined (APOLLO) || defined (WINDOWSNT) |
| 866 | /* // at start of filename is meaningful on Apollo | 904 | /* // at start of filename is meaningful on Apollo |
| 867 | and WindowsNT systems */ | 905 | and WindowsNT systems */ |
| 868 | && nm != p | 906 | && nm != p |
| 869 | #endif /* APOLLO || WINDOWSNT */ | 907 | #endif /* APOLLO || WINDOWSNT */ |
| 870 | ) | 908 | ) |
| 871 | nm = p + 1; | 909 | nm = p + 1; |
| 872 | 910 | ||
| 873 | /* "~" is hairy as the start of any path element. */ | ||
| 874 | if (IS_DIRECTORY_SEP (p[0]) && p[1] == '~') | 911 | if (IS_DIRECTORY_SEP (p[0]) && p[1] == '~') |
| 875 | nm = p + 1; | 912 | nm = p + 1; |
| 876 | 913 | ||
| 877 | p++; | 914 | p++; |
| 878 | } | 915 | } |
| 879 | 916 | ||
| 880 | /* If nm is absolute, flush ...// and detect /./ and /../. | 917 | #ifdef WINDOWSNT |
| 881 | If no /./ or /../ we can return right away. */ | 918 | /* Discard any previous drive specifier if nm is now in UNC format. */ |
| 919 | if (IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1])) | ||
| 920 | { | ||
| 921 | drive = 0; | ||
| 922 | } | ||
| 923 | #endif | ||
| 924 | |||
| 925 | /* If nm is absolute, look for /./ or /../ sequences; if none are | ||
| 926 | found, we can probably return right away. We will avoid allocating | ||
| 927 | a new string if name is already fully expanded. */ | ||
| 882 | if ( | 928 | if ( |
| 883 | IS_DIRECTORY_SEP (nm[0]) | 929 | IS_DIRECTORY_SEP (nm[0]) |
| 930 | #ifdef MSDOS | ||
| 931 | && drive | ||
| 932 | #endif | ||
| 933 | #ifdef WINDOWSNT | ||
| 934 | && (drive || IS_DIRECTORY_SEP (nm[1])) | ||
| 935 | #endif | ||
| 884 | #ifdef VMS | 936 | #ifdef VMS |
| 885 | || index (nm, ':') | 937 | || index (nm, ':') |
| 886 | #endif /* VMS */ | 938 | #endif /* VMS */ |
| @@ -897,7 +949,7 @@ See also the function `substitute-in-file-name'.") | |||
| 897 | p = nm; | 949 | p = nm; |
| 898 | while (*p) | 950 | while (*p) |
| 899 | { | 951 | { |
| 900 | /* Since we know the path is absolute, we can assume that each | 952 | /* Since we know the name is absolute, we can assume that each |
| 901 | element starts with a "/". */ | 953 | element starts with a "/". */ |
| 902 | 954 | ||
| 903 | /* "." and ".." are hairy. */ | 955 | /* "." and ".." are hairy. */ |
| @@ -957,7 +1009,7 @@ See also the function `substitute-in-file-name'.") | |||
| 957 | nm = brack + 1; | 1009 | nm = brack + 1; |
| 958 | brack = 0; | 1010 | brack = 0; |
| 959 | } | 1011 | } |
| 960 | /* if /pathname/dev:, move nm to dev: */ | 1012 | /* if /name/dev:, move nm to dev: */ |
| 961 | else if (slash) | 1013 | else if (slash) |
| 962 | nm = slash + 1; | 1014 | nm = slash + 1; |
| 963 | /* if node::dev:, move colon following dev */ | 1015 | /* if node::dev:, move colon following dev */ |
| @@ -989,7 +1041,28 @@ See also the function `substitute-in-file-name'.") | |||
| 989 | if (index (nm, '/')) | 1041 | if (index (nm, '/')) |
| 990 | return build_string (sys_translate_unix (nm)); | 1042 | return build_string (sys_translate_unix (nm)); |
| 991 | #endif /* VMS */ | 1043 | #endif /* VMS */ |
| 992 | #ifndef DOS_NT | 1044 | #ifdef DOS_NT |
| 1045 | /* Make sure directories are all separated with / or \ as | ||
| 1046 | desired, but avoid allocation of a new string when not | ||
| 1047 | required. */ | ||
| 1048 | CORRECT_DIR_SEPS (nm); | ||
| 1049 | #ifdef WINDOWSNT | ||
| 1050 | if (IS_DIRECTORY_SEP (nm[1])) | ||
| 1051 | { | ||
| 1052 | if (strcmp (nm, XSTRING (name)->data) != 0) | ||
| 1053 | name = build_string (nm); | ||
| 1054 | } | ||
| 1055 | else | ||
| 1056 | #endif | ||
| 1057 | /* drive must be set, so this is okay */ | ||
| 1058 | if (strcmp (nm - 2, XSTRING (name)->data) != 0) | ||
| 1059 | { | ||
| 1060 | name = make_string (nm - 2, p - nm + 2); | ||
| 1061 | XSTRING (name)->data[0] = drive; | ||
| 1062 | XSTRING (name)->data[1] = ':'; | ||
| 1063 | } | ||
| 1064 | return name; | ||
| 1065 | #else /* not DOS_NT */ | ||
| 993 | if (nm == XSTRING (name)->data) | 1066 | if (nm == XSTRING (name)->data) |
| 994 | return name; | 1067 | return name; |
| 995 | return build_string (nm); | 1068 | return build_string (nm); |
| @@ -997,7 +1070,21 @@ See also the function `substitute-in-file-name'.") | |||
| 997 | } | 1070 | } |
| 998 | } | 1071 | } |
| 999 | 1072 | ||
| 1000 | /* Now determine directory to start with and put it in newdir */ | 1073 | /* At this point, nm might or might not be an absolute file name. We |
| 1074 | need to expand ~ or ~user if present, otherwise prefix nm with | ||
| 1075 | default_directory if nm is not absolute, and finally collapse /./ | ||
| 1076 | and /foo/../ sequences. | ||
| 1077 | |||
| 1078 | We set newdir to be the appropriate prefix if one is needed: | ||
| 1079 | - the relevant user directory if nm starts with ~ or ~user | ||
| 1080 | - the specified drive's working dir (DOS/NT only) if nm does not | ||
| 1081 | start with / | ||
| 1082 | - the value of default_directory. | ||
| 1083 | |||
| 1084 | Note that these prefixes are not guaranteed to be absolute (except | ||
| 1085 | for the working dir of a drive). Therefore, to ensure we always | ||
| 1086 | return an absolute name, if the final prefix is not absolute we | ||
| 1087 | append it to the current working directory. */ | ||
| 1001 | 1088 | ||
| 1002 | newdir = 0; | 1089 | newdir = 0; |
| 1003 | 1090 | ||
| @@ -1011,14 +1098,12 @@ See also the function `substitute-in-file-name'.") | |||
| 1011 | { | 1098 | { |
| 1012 | if (!(newdir = (unsigned char *) egetenv ("HOME"))) | 1099 | if (!(newdir = (unsigned char *) egetenv ("HOME"))) |
| 1013 | newdir = (unsigned char *) ""; | 1100 | newdir = (unsigned char *) ""; |
| 1101 | nm++; | ||
| 1014 | #ifdef DOS_NT | 1102 | #ifdef DOS_NT |
| 1015 | /* Problem when expanding "~\" if HOME is not on current drive. | 1103 | if (IS_DIRECTORY_SEP (nm[0])) |
| 1016 | Ulrich Leodolter, Wed Jan 11 10:20:35 1995 */ | 1104 | /* Make nm look like a relative file name. */ |
| 1017 | if (newdir[1] == ':') | 1105 | nm++; |
| 1018 | drive = newdir[0]; | ||
| 1019 | dostounix_filename (newdir); | ||
| 1020 | #endif | 1106 | #endif |
| 1021 | nm++; | ||
| 1022 | #ifdef VMS | 1107 | #ifdef VMS |
| 1023 | nm++; /* Don't leave the slash in nm. */ | 1108 | nm++; /* Don't leave the slash in nm. */ |
| 1024 | #endif /* VMS */ | 1109 | #endif /* VMS */ |
| @@ -1034,10 +1119,6 @@ See also the function `substitute-in-file-name'.") | |||
| 1034 | bcopy ((char *) nm, o, p - nm); | 1119 | bcopy ((char *) nm, o, p - nm); |
| 1035 | o [p - nm] = 0; | 1120 | o [p - nm] = 0; |
| 1036 | 1121 | ||
| 1037 | #ifdef WINDOWSNT | ||
| 1038 | newdir = (unsigned char *) egetenv ("HOME"); | ||
| 1039 | dostounix_filename (newdir); | ||
| 1040 | #else /* not WINDOWSNT */ | ||
| 1041 | pw = (struct passwd *) getpwnam (o + 1); | 1122 | pw = (struct passwd *) getpwnam (o + 1); |
| 1042 | if (pw) | 1123 | if (pw) |
| 1043 | { | 1124 | { |
| @@ -1046,41 +1127,136 @@ See also the function `substitute-in-file-name'.") | |||
| 1046 | nm = p + 1; /* skip the terminator */ | 1127 | nm = p + 1; /* skip the terminator */ |
| 1047 | #else | 1128 | #else |
| 1048 | nm = p; | 1129 | nm = p; |
| 1130 | #ifdef DOS_NT | ||
| 1131 | if (IS_DIRECTORY_SEP (nm[0])) | ||
| 1132 | /* Make nm look like a relative name. */ | ||
| 1133 | nm++; | ||
| 1134 | #endif | ||
| 1049 | #endif /* VMS */ | 1135 | #endif /* VMS */ |
| 1050 | } | 1136 | } |
| 1051 | #endif /* not WINDOWSNT */ | ||
| 1052 | 1137 | ||
| 1053 | /* If we don't find a user of that name, leave the name | 1138 | /* If we don't find a user of that name, leave the name |
| 1054 | unchanged; don't move nm forward to p. */ | 1139 | unchanged; don't move nm forward to p. */ |
| 1055 | } | 1140 | } |
| 1056 | } | 1141 | } |
| 1057 | 1142 | ||
| 1058 | if (!IS_ANY_SEP (nm[0]) | ||
| 1059 | #ifdef VMS | ||
| 1060 | && !index (nm, ':') | ||
| 1061 | #endif /* not VMS */ | ||
| 1062 | #ifdef DOS_NT | 1143 | #ifdef DOS_NT |
| 1063 | && drive == -1 | 1144 | /* On DOS and Windows, nm is absolute if a drive name was specified; |
| 1145 | use the drive's current directory as the prefix if needed. */ | ||
| 1146 | if (!newdir && drive) | ||
| 1147 | { | ||
| 1148 | /* Get default directory if needed to make nm absolute. */ | ||
| 1149 | if (!IS_DIRECTORY_SEP (nm[0])) | ||
| 1150 | { | ||
| 1151 | newdir = alloca (MAXPATHLEN + 1); | ||
| 1152 | if (!getdefdir (toupper (drive) - 'A' + 1, newdir)) | ||
| 1153 | newdir = NULL; | ||
| 1154 | } | ||
| 1155 | if (!newdir) | ||
| 1156 | { | ||
| 1157 | /* Either nm starts with /, or drive isn't mounted. */ | ||
| 1158 | newdir = alloca (4); | ||
| 1159 | newdir[0] = drive; | ||
| 1160 | newdir[1] = ':'; | ||
| 1161 | newdir[2] = '/'; | ||
| 1162 | newdir[3] = 0; | ||
| 1163 | } | ||
| 1164 | } | ||
| 1064 | #endif /* DOS_NT */ | 1165 | #endif /* DOS_NT */ |
| 1166 | |||
| 1167 | /* Finally, if no prefix has been specified and nm is not absolute, | ||
| 1168 | then it must be expanded relative to default_directory. */ | ||
| 1169 | |||
| 1170 | if ( | ||
| 1171 | #ifndef DOS_NT | ||
| 1172 | /* /... alone is not absolute on DOS and Windows. */ | ||
| 1173 | !IS_DIRECTORY_SEP (nm[0]) | ||
| 1174 | #endif | ||
| 1175 | #ifdef WINDOWSNT | ||
| 1176 | !(IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1])) | ||
| 1177 | #endif | ||
| 1178 | #ifdef VMS | ||
| 1179 | && !index (nm, ':') | ||
| 1180 | #endif | ||
| 1065 | && !newdir) | 1181 | && !newdir) |
| 1066 | { | 1182 | { |
| 1067 | newdir = XSTRING (default_directory)->data; | 1183 | newdir = XSTRING (default_directory)->data; |
| 1068 | } | 1184 | } |
| 1069 | 1185 | ||
| 1070 | #ifdef DOS_NT | 1186 | #ifdef DOS_NT |
| 1071 | if (newdir == 0 && relpath) | 1187 | if (newdir) |
| 1072 | newdir = defdir; | 1188 | { |
| 1189 | /* First ensure newdir is an absolute name. */ | ||
| 1190 | if ( | ||
| 1191 | /* Detect MSDOS file names with drive specifiers. */ | ||
| 1192 | ! (IS_DRIVE (newdir[0]) | ||
| 1193 | && IS_DEVICE_SEP (newdir[1]) && IS_DIRECTORY_SEP (newdir[2])) | ||
| 1194 | #ifdef WINDOWSNT | ||
| 1195 | /* Detect Windows file names in UNC format. */ | ||
| 1196 | && ! (IS_DIRECTORY_SEP (newdir[0]) && IS_DIRECTORY_SEP (newdir[1])) | ||
| 1197 | #endif | ||
| 1198 | ) | ||
| 1199 | { | ||
| 1200 | /* Effectively, let newdir be (expand-file-name newdir cwd). | ||
| 1201 | Because of the admonition against calling expand-file-name | ||
| 1202 | when we have pointers into lisp strings, we accomplish this | ||
| 1203 | indirectly by prepending newdir to nm if necessary, and using | ||
| 1204 | cwd (or the wd of newdir's drive) as the new newdir. */ | ||
| 1205 | |||
| 1206 | if (IS_DRIVE (newdir[0]) && newdir[1] == ':') | ||
| 1207 | { | ||
| 1208 | drive = newdir[0]; | ||
| 1209 | newdir += 2; | ||
| 1210 | } | ||
| 1211 | if (!IS_DIRECTORY_SEP (nm[0])) | ||
| 1212 | { | ||
| 1213 | char * tmp = alloca (strlen (newdir) + strlen (nm) + 2); | ||
| 1214 | file_name_as_directory (tmp, newdir); | ||
| 1215 | strcat (tmp, nm); | ||
| 1216 | nm = tmp; | ||
| 1217 | } | ||
| 1218 | newdir = alloca (MAXPATHLEN + 1); | ||
| 1219 | if (drive) | ||
| 1220 | { | ||
| 1221 | if (!getdefdir (toupper (drive) - 'A' + 1, newdir)) | ||
| 1222 | newdir = "/"; | ||
| 1223 | } | ||
| 1224 | else | ||
| 1225 | getwd (newdir); | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | /* Strip off drive name from prefix, if present. */ | ||
| 1229 | if (IS_DRIVE (newdir[0]) && newdir[1] == ':') | ||
| 1230 | { | ||
| 1231 | drive = newdir[0]; | ||
| 1232 | newdir += 2; | ||
| 1233 | } | ||
| 1234 | |||
| 1235 | /* Keep only a prefix from newdir if nm starts with slash | ||
| 1236 | (//server/share for UNC, nothing otherwise). */ | ||
| 1237 | if (IS_DIRECTORY_SEP (nm[0])) | ||
| 1238 | { | ||
| 1239 | #ifdef WINDOWSNT | ||
| 1240 | if (IS_DIRECTORY_SEP (newdir[0]) && IS_DIRECTORY_SEP (newdir[1])) | ||
| 1241 | { | ||
| 1242 | newdir = strcpy (alloca (strlen (newdir) + 1), newdir); | ||
| 1243 | p = newdir + 2; | ||
| 1244 | while (*p && !IS_DIRECTORY_SEP (*p)) p++; | ||
| 1245 | p++; | ||
| 1246 | while (*p && !IS_DIRECTORY_SEP (*p)) p++; | ||
| 1247 | *p = 0; | ||
| 1248 | } | ||
| 1249 | else | ||
| 1250 | #endif | ||
| 1251 | newdir = ""; | ||
| 1252 | } | ||
| 1253 | } | ||
| 1073 | #endif /* DOS_NT */ | 1254 | #endif /* DOS_NT */ |
| 1074 | if (newdir != 0) | 1255 | |
| 1256 | if (newdir) | ||
| 1075 | { | 1257 | { |
| 1076 | /* Get rid of any slash at the end of newdir. */ | 1258 | /* Get rid of any slash at the end of newdir. */ |
| 1077 | int length = strlen (newdir); | 1259 | length = strlen (newdir); |
| 1078 | /* Adding `length > 1 &&' makes ~ expand into / when homedir | ||
| 1079 | is the root dir. People disagree about whether that is right. | ||
| 1080 | Anyway, we can't take the risk of this change now. */ | ||
| 1081 | #ifdef DOS_NT | ||
| 1082 | if (newdir[1] != ':' && length > 1) | ||
| 1083 | #endif | ||
| 1084 | if (IS_DIRECTORY_SEP (newdir[length - 1])) | 1260 | if (IS_DIRECTORY_SEP (newdir[length - 1])) |
| 1085 | { | 1261 | { |
| 1086 | unsigned char *temp = (unsigned char *) alloca (length); | 1262 | unsigned char *temp = (unsigned char *) alloca (length); |
| @@ -1096,7 +1272,7 @@ See also the function `substitute-in-file-name'.") | |||
| 1096 | /* Now concatenate the directory and name to new space in the stack frame */ | 1272 | /* Now concatenate the directory and name to new space in the stack frame */ |
| 1097 | tlen += strlen (nm) + 1; | 1273 | tlen += strlen (nm) + 1; |
| 1098 | #ifdef DOS_NT | 1274 | #ifdef DOS_NT |
| 1099 | /* Add reserved space for drive name. (The Microsoft x86 compiler | 1275 | /* Add reserved space for drive name. (The Microsoft x86 compiler |
| 1100 | produces incorrect code if the following two lines are combined.) */ | 1276 | produces incorrect code if the following two lines are combined.) */ |
| 1101 | target = (unsigned char *) alloca (tlen + 2); | 1277 | target = (unsigned char *) alloca (tlen + 2); |
| 1102 | target += 2; | 1278 | target += 2; |
| @@ -1121,6 +1297,8 @@ See also the function `substitute-in-file-name'.") | |||
| 1121 | strcpy (target, sys_translate_unix (target)); | 1297 | strcpy (target, sys_translate_unix (target)); |
| 1122 | #endif /* VMS */ | 1298 | #endif /* VMS */ |
| 1123 | 1299 | ||
| 1300 | /* ASSERT (IS_DIRECTORY_SEP (target[0])) if not VMS */ | ||
| 1301 | |||
| 1124 | /* Now canonicalize by removing /. and /foo/.. if they appear. */ | 1302 | /* Now canonicalize by removing /. and /foo/.. if they appear. */ |
| 1125 | 1303 | ||
| 1126 | p = target; | 1304 | p = target; |
| @@ -1176,10 +1354,10 @@ See also the function `substitute-in-file-name'.") | |||
| 1176 | } | 1354 | } |
| 1177 | else if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1]) | 1355 | else if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1]) |
| 1178 | #if defined (APOLLO) || defined (WINDOWSNT) | 1356 | #if defined (APOLLO) || defined (WINDOWSNT) |
| 1179 | /* // at start of filename is meaningful in Apollo | 1357 | /* // at start of filename is meaningful in Apollo |
| 1180 | and WindowsNT systems */ | 1358 | and WindowsNT systems */ |
| 1181 | && o != target | 1359 | && o != target |
| 1182 | #endif /* APOLLO */ | 1360 | #endif /* APOLLO || WINDOWSNT */ |
| 1183 | ) | 1361 | ) |
| 1184 | { | 1362 | { |
| 1185 | o = target; | 1363 | o = target; |
| @@ -1203,14 +1381,6 @@ See also the function `substitute-in-file-name'.") | |||
| 1203 | { | 1381 | { |
| 1204 | while (o != target && (--o) && !IS_DIRECTORY_SEP (*o)) | 1382 | while (o != target && (--o) && !IS_DIRECTORY_SEP (*o)) |
| 1205 | ; | 1383 | ; |
| 1206 | #if defined (APOLLO) || defined (WINDOWSNT) | ||
| 1207 | if (o == target + 1 | ||
| 1208 | && IS_DIRECTORY_SEP (o[-1]) && IS_DIRECTORY_SEP (o[0])) | ||
| 1209 | ++o; | ||
| 1210 | else | ||
| 1211 | #endif /* APOLLO || WINDOWSNT */ | ||
| 1212 | if (o == target && IS_ANY_SEP (*o)) | ||
| 1213 | ++o; | ||
| 1214 | p += 3; | 1384 | p += 3; |
| 1215 | } | 1385 | } |
| 1216 | else | 1386 | else |
| @@ -1221,18 +1391,18 @@ See also the function `substitute-in-file-name'.") | |||
| 1221 | } | 1391 | } |
| 1222 | 1392 | ||
| 1223 | #ifdef DOS_NT | 1393 | #ifdef DOS_NT |
| 1224 | /* at last, set drive name. */ | 1394 | /* At last, set drive name. */ |
| 1225 | if (target[1] != ':' | ||
| 1226 | #ifdef WINDOWSNT | 1395 | #ifdef WINDOWSNT |
| 1227 | /* Allow network paths that look like "\\foo" */ | 1396 | /* Except for network file name. */ |
| 1228 | && !(IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1])) | 1397 | if (!(IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))) |
| 1229 | #endif /* WINDOWSNT */ | 1398 | #endif /* WINDOWSNT */ |
| 1230 | ) | ||
| 1231 | { | 1399 | { |
| 1400 | if (!drive) abort (); | ||
| 1232 | target -= 2; | 1401 | target -= 2; |
| 1233 | target[0] = (drive < 0 ? getdisk () + 'A' : drive); | 1402 | target[0] = drive; |
| 1234 | target[1] = ':'; | 1403 | target[1] = ':'; |
| 1235 | } | 1404 | } |
| 1405 | CORRECT_DIR_SEPS (target); | ||
| 1236 | #endif /* DOS_NT */ | 1406 | #endif /* DOS_NT */ |
| 1237 | 1407 | ||
| 1238 | return make_string (target, o - target); | 1408 | return make_string (target, o - target); |
| @@ -1252,7 +1422,7 @@ See also the function `substitute-in-file-name'.") | |||
| 1252 | Lisp_Object name, defalt; | 1422 | Lisp_Object name, defalt; |
| 1253 | { | 1423 | { |
| 1254 | unsigned char *nm; | 1424 | unsigned char *nm; |
| 1255 | 1425 | ||
| 1256 | register unsigned char *newdir, *p, *o; | 1426 | register unsigned char *newdir, *p, *o; |
| 1257 | int tlen; | 1427 | int tlen; |
| 1258 | unsigned char *target; | 1428 | unsigned char *target; |
| @@ -1266,7 +1436,7 @@ See also the function `substitute-in-file-name'.") | |||
| 1266 | int lbrack = 0, rbrack = 0; | 1436 | int lbrack = 0, rbrack = 0; |
| 1267 | int dots = 0; | 1437 | int dots = 0; |
| 1268 | #endif /* VMS */ | 1438 | #endif /* VMS */ |
| 1269 | 1439 | ||
| 1270 | CHECK_STRING (name, 0); | 1440 | CHECK_STRING (name, 0); |
| 1271 | 1441 | ||
| 1272 | #ifdef VMS | 1442 | #ifdef VMS |
| @@ -1275,7 +1445,7 @@ See also the function `substitute-in-file-name'.") | |||
| 1275 | #endif | 1445 | #endif |
| 1276 | 1446 | ||
| 1277 | nm = XSTRING (name)->data; | 1447 | nm = XSTRING (name)->data; |
| 1278 | 1448 | ||
| 1279 | /* If nm is absolute, flush ...// and detect /./ and /../. | 1449 | /* If nm is absolute, flush ...// and detect /./ and /../. |
| 1280 | If no /./ or /../ we can return right away. */ | 1450 | If no /./ or /../ we can return right away. */ |
| 1281 | if ( | 1451 | if ( |
| @@ -1351,13 +1521,13 @@ See also the function `substitute-in-file-name'.") | |||
| 1351 | nm = brack + 1; | 1521 | nm = brack + 1; |
| 1352 | brack = 0; | 1522 | brack = 0; |
| 1353 | } | 1523 | } |
| 1354 | /* if /pathname/dev:, move nm to dev: */ | 1524 | /* If /name/dev:, move nm to dev: */ |
| 1355 | else if (slash) | 1525 | else if (slash) |
| 1356 | nm = slash + 1; | 1526 | nm = slash + 1; |
| 1357 | /* if node::dev:, move colon following dev */ | 1527 | /* If node::dev:, move colon following dev */ |
| 1358 | else if (colon && colon[-1] == ':') | 1528 | else if (colon && colon[-1] == ':') |
| 1359 | colon = p; | 1529 | colon = p; |
| 1360 | /* if dev1:dev2:, move nm to dev2: */ | 1530 | /* If dev1:dev2:, move nm to dev2: */ |
| 1361 | else if (colon && colon[-1] != ':') | 1531 | else if (colon && colon[-1] != ':') |
| 1362 | { | 1532 | { |
| 1363 | nm = colon + 1; | 1533 | nm = colon + 1; |
| @@ -1593,9 +1763,10 @@ duplicates what `expand-file-name' does.") | |||
| 1593 | return call2 (handler, Qsubstitute_in_file_name, filename); | 1763 | return call2 (handler, Qsubstitute_in_file_name, filename); |
| 1594 | 1764 | ||
| 1595 | nm = XSTRING (filename)->data; | 1765 | nm = XSTRING (filename)->data; |
| 1596 | #ifdef MSDOS | 1766 | #ifdef DOS_NT |
| 1597 | dostounix_filename (nm = strcpy (alloca (strlen (nm) + 1), nm)); | 1767 | nm = strcpy (alloca (strlen (nm) + 1), nm); |
| 1598 | substituted = !strcmp (nm, XSTRING (filename)->data); | 1768 | CORRECT_DIR_SEPS (nm); |
| 1769 | substituted = (strcmp (nm, XSTRING (filename)->data) != 0); | ||
| 1599 | #endif | 1770 | #endif |
| 1600 | endp = nm + XSTRING (filename)->size; | 1771 | endp = nm + XSTRING (filename)->size; |
| 1601 | 1772 | ||
| @@ -1603,17 +1774,14 @@ duplicates what `expand-file-name' does.") | |||
| 1603 | 1774 | ||
| 1604 | for (p = nm; p != endp; p++) | 1775 | for (p = nm; p != endp; p++) |
| 1605 | { | 1776 | { |
| 1606 | if ((p[0] == '~' || | 1777 | if ((p[0] == '~' |
| 1607 | #ifdef APOLLO | 1778 | #if defined (APOLLO) || defined (WINDOWSNT) |
| 1608 | /* // at start of file name is meaningful in Apollo system */ | 1779 | /* // at start of file name is meaningful in Apollo and |
| 1609 | (p[0] == '/' && p - 1 != nm) | 1780 | WindowsNT systems */ |
| 1610 | #else /* not APOLLO */ | 1781 | || (IS_DIRECTORY_SEP (p[0]) && p - 1 != nm) |
| 1611 | #ifdef WINDOWSNT | 1782 | #else /* not (APOLLO || WINDOWSNT) */ |
| 1612 | (IS_DIRECTORY_SEP (p[0]) && p - 1 != nm) | 1783 | || IS_DIRECTORY_SEP (p[0]) |
| 1613 | #else /* not WINDOWSNT */ | 1784 | #endif /* not (APOLLO || WINDOWSNT) */ |
| 1614 | p[0] == '/' | ||
| 1615 | #endif /* not WINDOWSNT */ | ||
| 1616 | #endif /* not APOLLO */ | ||
| 1617 | ) | 1785 | ) |
| 1618 | && p != nm | 1786 | && p != nm |
| 1619 | && (0 | 1787 | && (0 |
| @@ -1626,7 +1794,9 @@ duplicates what `expand-file-name' does.") | |||
| 1626 | substituted = 1; | 1794 | substituted = 1; |
| 1627 | } | 1795 | } |
| 1628 | #ifdef DOS_NT | 1796 | #ifdef DOS_NT |
| 1629 | if (p[0] && p[1] == ':') | 1797 | /* see comment in expand-file-name about drive specifiers */ |
| 1798 | else if (IS_DRIVE (p[0]) && p[1] == ':' | ||
| 1799 | && p > nm && IS_DIRECTORY_SEP (p[-1])) | ||
| 1630 | { | 1800 | { |
| 1631 | nm = p; | 1801 | nm = p; |
| 1632 | substituted = 1; | 1802 | substituted = 1; |
| @@ -1745,22 +1915,18 @@ duplicates what `expand-file-name' does.") | |||
| 1745 | 1915 | ||
| 1746 | for (p = xnm; p != x; p++) | 1916 | for (p = xnm; p != x; p++) |
| 1747 | if ((p[0] == '~' | 1917 | if ((p[0] == '~' |
| 1748 | #ifdef APOLLO | 1918 | #if defined (APOLLO) || defined (WINDOWSNT) |
| 1749 | /* // at start of file name is meaningful in Apollo system */ | ||
| 1750 | || (p[0] == '/' && p - 1 != xnm) | ||
| 1751 | #else /* not APOLLO */ | ||
| 1752 | #ifdef WINDOWSNT | ||
| 1753 | || (IS_DIRECTORY_SEP (p[0]) && p - 1 != xnm) | 1919 | || (IS_DIRECTORY_SEP (p[0]) && p - 1 != xnm) |
| 1754 | #else /* not WINDOWSNT */ | 1920 | #else /* not (APOLLO || WINDOWSNT) */ |
| 1755 | || p[0] == '/' | 1921 | || IS_DIRECTORY_SEP (p[0]) |
| 1756 | #endif /* not WINDOWSNT */ | 1922 | #endif /* not (APOLLO || WINDOWSNT) */ |
| 1757 | #endif /* not APOLLO */ | ||
| 1758 | ) | 1923 | ) |
| 1759 | && p != nm && IS_DIRECTORY_SEP (p[-1])) | 1924 | && p != nm && IS_DIRECTORY_SEP (p[-1])) |
| 1760 | xnm = p; | 1925 | xnm = p; |
| 1761 | #ifdef DOS_NT | 1926 | #ifdef DOS_NT |
| 1762 | else if (p[0] && p[1] == ':') | 1927 | else if (IS_DRIVE (p[0]) && p[1] == ':' |
| 1763 | xnm = p; | 1928 | && p > nm && IS_DIRECTORY_SEP (p[-1])) |
| 1929 | xnm = p; | ||
| 1764 | #endif | 1930 | #endif |
| 1765 | 1931 | ||
| 1766 | return make_string (xnm, x - xnm); | 1932 | return make_string (xnm, x - xnm); |
| @@ -1783,25 +1949,25 @@ Lisp_Object | |||
| 1783 | expand_and_dir_to_file (filename, defdir) | 1949 | expand_and_dir_to_file (filename, defdir) |
| 1784 | Lisp_Object filename, defdir; | 1950 | Lisp_Object filename, defdir; |
| 1785 | { | 1951 | { |
| 1786 | register Lisp_Object abspath; | 1952 | register Lisp_Object absname; |
| 1787 | 1953 | ||
| 1788 | abspath = Fexpand_file_name (filename, defdir); | 1954 | absname = Fexpand_file_name (filename, defdir); |
| 1789 | #ifdef VMS | 1955 | #ifdef VMS |
| 1790 | { | 1956 | { |
| 1791 | register int c = XSTRING (abspath)->data[XSTRING (abspath)->size - 1]; | 1957 | register int c = XSTRING (absname)->data[XSTRING (absname)->size - 1]; |
| 1792 | if (c == ':' || c == ']' || c == '>') | 1958 | if (c == ':' || c == ']' || c == '>') |
| 1793 | abspath = Fdirectory_file_name (abspath); | 1959 | absname = Fdirectory_file_name (absname); |
| 1794 | } | 1960 | } |
| 1795 | #else | 1961 | #else |
| 1796 | /* Remove final slash, if any (unless path is root). | 1962 | /* Remove final slash, if any (unless this is the root dir). |
| 1797 | stat behaves differently depending! */ | 1963 | stat behaves differently depending! */ |
| 1798 | if (XSTRING (abspath)->size > 1 | 1964 | if (XSTRING (absname)->size > 1 |
| 1799 | && IS_DIRECTORY_SEP (XSTRING (abspath)->data[XSTRING (abspath)->size - 1]) | 1965 | && IS_DIRECTORY_SEP (XSTRING (absname)->data[XSTRING (absname)->size - 1]) |
| 1800 | && !IS_DEVICE_SEP (XSTRING (abspath)->data[XSTRING (abspath)->size-2])) | 1966 | && !IS_DEVICE_SEP (XSTRING (absname)->data[XSTRING (absname)->size-2])) |
| 1801 | /* We cannot take shortcuts; they might be wrong for magic file names. */ | 1967 | /* We cannot take shortcuts; they might be wrong for magic file names. */ |
| 1802 | abspath = Fdirectory_file_name (abspath); | 1968 | absname = Fdirectory_file_name (absname); |
| 1803 | #endif | 1969 | #endif |
| 1804 | return abspath; | 1970 | return absname; |
| 1805 | } | 1971 | } |
| 1806 | 1972 | ||
| 1807 | /* Signal an error if the file ABSNAME already exists. | 1973 | /* Signal an error if the file ABSNAME already exists. |
| @@ -1904,7 +2070,7 @@ A prefix arg makes KEEP-TIME non-nil.") | |||
| 1904 | copyable by us. */ | 2070 | copyable by us. */ |
| 1905 | input_file_statable_p = (fstat (ifd, &st) >= 0); | 2071 | input_file_statable_p = (fstat (ifd, &st) >= 0); |
| 1906 | 2072 | ||
| 1907 | #ifndef DOS_NT | 2073 | #ifndef MSDOS |
| 1908 | if (out_st.st_mode != 0 | 2074 | if (out_st.st_mode != 0 |
| 1909 | && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino) | 2075 | && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino) |
| 1910 | { | 2076 | { |
| @@ -2308,10 +2474,10 @@ DEFUN ("sysnetunam", Fsysnetunam, Ssysnetunam, 2, 2, 0, | |||
| 2308 | Lisp_Object path, login; | 2474 | Lisp_Object path, login; |
| 2309 | { | 2475 | { |
| 2310 | int netresult; | 2476 | int netresult; |
| 2311 | 2477 | ||
| 2312 | CHECK_STRING (path, 0); | 2478 | CHECK_STRING (path, 0); |
| 2313 | CHECK_STRING (login, 0); | 2479 | CHECK_STRING (login, 0); |
| 2314 | 2480 | ||
| 2315 | netresult = netunam (XSTRING (path)->data, XSTRING (login)->data); | 2481 | netresult = netunam (XSTRING (path)->data, XSTRING (login)->data); |
| 2316 | 2482 | ||
| 2317 | if (netresult == -1) | 2483 | if (netresult == -1) |
| @@ -2323,7 +2489,7 @@ DEFUN ("sysnetunam", Fsysnetunam, Ssysnetunam, 2, 2, 0, | |||
| 2323 | 2489 | ||
| 2324 | DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p, | 2490 | DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p, |
| 2325 | 1, 1, 0, | 2491 | 1, 1, 0, |
| 2326 | "Return t if file FILENAME specifies an absolute path name.\n\ | 2492 | "Return t if file FILENAME specifies an absolute file name.\n\ |
| 2327 | On Unix, this is a name starting with a `/' or a `~'.") | 2493 | On Unix, this is a name starting with a `/' or a `~'.") |
| 2328 | (filename) | 2494 | (filename) |
| 2329 | Lisp_Object filename; | 2495 | Lisp_Object filename; |
| @@ -2340,7 +2506,7 @@ On Unix, this is a name starting with a `/' or a `~'.") | |||
| 2340 | && ptr[1] != '.') | 2506 | && ptr[1] != '.') |
| 2341 | #endif /* VMS */ | 2507 | #endif /* VMS */ |
| 2342 | #ifdef DOS_NT | 2508 | #ifdef DOS_NT |
| 2343 | || (*ptr != 0 && ptr[1] == ':' && (ptr[2] == '/' || ptr[2] == '\\')) | 2509 | || (IS_DRIVE (*ptr) && ptr[1] == ':' && IS_DIRECTORY_SEP (ptr[2])) |
| 2344 | #endif | 2510 | #endif |
| 2345 | ) | 2511 | ) |
| 2346 | return Qt; | 2512 | return Qt; |
| @@ -2360,12 +2526,16 @@ check_executable (filename) | |||
| 2360 | struct stat st; | 2526 | struct stat st; |
| 2361 | if (stat (filename, &st) < 0) | 2527 | if (stat (filename, &st) < 0) |
| 2362 | return 0; | 2528 | return 0; |
| 2529 | #ifdef WINDOWSNT | ||
| 2530 | return ((st.st_mode & S_IEXEC) != 0); | ||
| 2531 | #else | ||
| 2363 | return (S_ISREG (st.st_mode) | 2532 | return (S_ISREG (st.st_mode) |
| 2364 | && len >= 5 | 2533 | && len >= 5 |
| 2365 | && (stricmp ((suffix = filename + len-4), ".com") == 0 | 2534 | && (stricmp ((suffix = filename + len-4), ".com") == 0 |
| 2366 | || stricmp (suffix, ".exe") == 0 | 2535 | || stricmp (suffix, ".exe") == 0 |
| 2367 | || stricmp (suffix, ".bat") == 0) | 2536 | || stricmp (suffix, ".bat") == 0) |
| 2368 | || (st.st_mode & S_IFMT) == S_IFDIR); | 2537 | || (st.st_mode & S_IFMT) == S_IFDIR); |
| 2538 | #endif /* not WINDOWSNT */ | ||
| 2369 | #else /* not DOS_NT */ | 2539 | #else /* not DOS_NT */ |
| 2370 | #ifdef HAVE_EACCESS | 2540 | #ifdef HAVE_EACCESS |
| 2371 | return (eaccess (filename, 1) >= 0); | 2541 | return (eaccess (filename, 1) >= 0); |
| @@ -2409,20 +2579,20 @@ See also `file-readable-p' and `file-attributes'.") | |||
| 2409 | (filename) | 2579 | (filename) |
| 2410 | Lisp_Object filename; | 2580 | Lisp_Object filename; |
| 2411 | { | 2581 | { |
| 2412 | Lisp_Object abspath; | 2582 | Lisp_Object absname; |
| 2413 | Lisp_Object handler; | 2583 | Lisp_Object handler; |
| 2414 | struct stat statbuf; | 2584 | struct stat statbuf; |
| 2415 | 2585 | ||
| 2416 | CHECK_STRING (filename, 0); | 2586 | CHECK_STRING (filename, 0); |
| 2417 | abspath = Fexpand_file_name (filename, Qnil); | 2587 | absname = Fexpand_file_name (filename, Qnil); |
| 2418 | 2588 | ||
| 2419 | /* If the file name has special constructs in it, | 2589 | /* If the file name has special constructs in it, |
| 2420 | call the corresponding file handler. */ | 2590 | call the corresponding file handler. */ |
| 2421 | handler = Ffind_file_name_handler (abspath, Qfile_exists_p); | 2591 | handler = Ffind_file_name_handler (absname, Qfile_exists_p); |
| 2422 | if (!NILP (handler)) | 2592 | if (!NILP (handler)) |
| 2423 | return call2 (handler, Qfile_exists_p, abspath); | 2593 | return call2 (handler, Qfile_exists_p, absname); |
| 2424 | 2594 | ||
| 2425 | return (stat (XSTRING (abspath)->data, &statbuf) >= 0) ? Qt : Qnil; | 2595 | return (stat (XSTRING (absname)->data, &statbuf) >= 0) ? Qt : Qnil; |
| 2426 | } | 2596 | } |
| 2427 | 2597 | ||
| 2428 | DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0, | 2598 | DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0, |
| @@ -2432,19 +2602,19 @@ For a directory, this means you can access files in that directory.") | |||
| 2432 | Lisp_Object filename; | 2602 | Lisp_Object filename; |
| 2433 | 2603 | ||
| 2434 | { | 2604 | { |
| 2435 | Lisp_Object abspath; | 2605 | Lisp_Object absname; |
| 2436 | Lisp_Object handler; | 2606 | Lisp_Object handler; |
| 2437 | 2607 | ||
| 2438 | CHECK_STRING (filename, 0); | 2608 | CHECK_STRING (filename, 0); |
| 2439 | abspath = Fexpand_file_name (filename, Qnil); | 2609 | absname = Fexpand_file_name (filename, Qnil); |
| 2440 | 2610 | ||
| 2441 | /* If the file name has special constructs in it, | 2611 | /* If the file name has special constructs in it, |
| 2442 | call the corresponding file handler. */ | 2612 | call the corresponding file handler. */ |
| 2443 | handler = Ffind_file_name_handler (abspath, Qfile_executable_p); | 2613 | handler = Ffind_file_name_handler (absname, Qfile_executable_p); |
| 2444 | if (!NILP (handler)) | 2614 | if (!NILP (handler)) |
| 2445 | return call2 (handler, Qfile_executable_p, abspath); | 2615 | return call2 (handler, Qfile_executable_p, absname); |
| 2446 | 2616 | ||
| 2447 | return (check_executable (XSTRING (abspath)->data) ? Qt : Qnil); | 2617 | return (check_executable (XSTRING (absname)->data) ? Qt : Qnil); |
| 2448 | } | 2618 | } |
| 2449 | 2619 | ||
| 2450 | DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0, | 2620 | DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0, |
| @@ -2453,32 +2623,31 @@ See also `file-exists-p' and `file-attributes'.") | |||
| 2453 | (filename) | 2623 | (filename) |
| 2454 | Lisp_Object filename; | 2624 | Lisp_Object filename; |
| 2455 | { | 2625 | { |
| 2456 | Lisp_Object abspath; | 2626 | Lisp_Object absname; |
| 2457 | Lisp_Object handler; | 2627 | Lisp_Object handler; |
| 2458 | int desc; | 2628 | int desc; |
| 2459 | 2629 | ||
| 2460 | CHECK_STRING (filename, 0); | 2630 | CHECK_STRING (filename, 0); |
| 2461 | abspath = Fexpand_file_name (filename, Qnil); | 2631 | absname = Fexpand_file_name (filename, Qnil); |
| 2462 | 2632 | ||
| 2463 | /* If the file name has special constructs in it, | 2633 | /* If the file name has special constructs in it, |
| 2464 | call the corresponding file handler. */ | 2634 | call the corresponding file handler. */ |
| 2465 | handler = Ffind_file_name_handler (abspath, Qfile_readable_p); | 2635 | handler = Ffind_file_name_handler (absname, Qfile_readable_p); |
| 2466 | if (!NILP (handler)) | 2636 | if (!NILP (handler)) |
| 2467 | return call2 (handler, Qfile_readable_p, abspath); | 2637 | return call2 (handler, Qfile_readable_p, absname); |
| 2468 | 2638 | ||
| 2469 | #ifdef MSDOS | 2639 | #ifdef DOS_NT |
| 2470 | /* Under MS-DOS, open does not work't right, because it doesn't work for | 2640 | /* Under MS-DOS and Windows, open does not work for directories. */ |
| 2471 | directories (MS-DOS won't let you open a directory). */ | 2641 | if (access (XSTRING (absname)->data, 0) == 0) |
| 2472 | if (access (XSTRING (abspath)->data, 0) == 0) | ||
| 2473 | return Qt; | 2642 | return Qt; |
| 2474 | return Qnil; | 2643 | return Qnil; |
| 2475 | #else /* not MSDOS */ | 2644 | #else /* not DOS_NT */ |
| 2476 | desc = open (XSTRING (abspath)->data, O_RDONLY); | 2645 | desc = open (XSTRING (absname)->data, O_RDONLY); |
| 2477 | if (desc < 0) | 2646 | if (desc < 0) |
| 2478 | return Qnil; | 2647 | return Qnil; |
| 2479 | close (desc); | 2648 | close (desc); |
| 2480 | return Qt; | 2649 | return Qt; |
| 2481 | #endif /* not MSDOS */ | 2650 | #endif /* not DOS_NT */ |
| 2482 | } | 2651 | } |
| 2483 | 2652 | ||
| 2484 | /* Having this before file-symlink-p mysteriously caused it to be forgotten | 2653 | /* Having this before file-symlink-p mysteriously caused it to be forgotten |
| @@ -2488,23 +2657,23 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, | |||
| 2488 | (filename) | 2657 | (filename) |
| 2489 | Lisp_Object filename; | 2658 | Lisp_Object filename; |
| 2490 | { | 2659 | { |
| 2491 | Lisp_Object abspath, dir; | 2660 | Lisp_Object absname, dir; |
| 2492 | Lisp_Object handler; | 2661 | Lisp_Object handler; |
| 2493 | struct stat statbuf; | 2662 | struct stat statbuf; |
| 2494 | 2663 | ||
| 2495 | CHECK_STRING (filename, 0); | 2664 | CHECK_STRING (filename, 0); |
| 2496 | abspath = Fexpand_file_name (filename, Qnil); | 2665 | absname = Fexpand_file_name (filename, Qnil); |
| 2497 | 2666 | ||
| 2498 | /* If the file name has special constructs in it, | 2667 | /* If the file name has special constructs in it, |
| 2499 | call the corresponding file handler. */ | 2668 | call the corresponding file handler. */ |
| 2500 | handler = Ffind_file_name_handler (abspath, Qfile_writable_p); | 2669 | handler = Ffind_file_name_handler (absname, Qfile_writable_p); |
| 2501 | if (!NILP (handler)) | 2670 | if (!NILP (handler)) |
| 2502 | return call2 (handler, Qfile_writable_p, abspath); | 2671 | return call2 (handler, Qfile_writable_p, absname); |
| 2503 | 2672 | ||
| 2504 | if (stat (XSTRING (abspath)->data, &statbuf) >= 0) | 2673 | if (stat (XSTRING (absname)->data, &statbuf) >= 0) |
| 2505 | return (check_writable (XSTRING (abspath)->data) | 2674 | return (check_writable (XSTRING (absname)->data) |
| 2506 | ? Qt : Qnil); | 2675 | ? Qt : Qnil); |
| 2507 | dir = Ffile_name_directory (abspath); | 2676 | dir = Ffile_name_directory (absname); |
| 2508 | #ifdef VMS | 2677 | #ifdef VMS |
| 2509 | if (!NILP (dir)) | 2678 | if (!NILP (dir)) |
| 2510 | dir = Fdirectory_file_name (dir); | 2679 | dir = Fdirectory_file_name (dir); |
| @@ -2571,19 +2740,19 @@ if the directory so specified exists and really is a directory.") | |||
| 2571 | (filename) | 2740 | (filename) |
| 2572 | Lisp_Object filename; | 2741 | Lisp_Object filename; |
| 2573 | { | 2742 | { |
| 2574 | register Lisp_Object abspath; | 2743 | register Lisp_Object absname; |
| 2575 | struct stat st; | 2744 | struct stat st; |
| 2576 | Lisp_Object handler; | 2745 | Lisp_Object handler; |
| 2577 | 2746 | ||
| 2578 | abspath = expand_and_dir_to_file (filename, current_buffer->directory); | 2747 | absname = expand_and_dir_to_file (filename, current_buffer->directory); |
| 2579 | 2748 | ||
| 2580 | /* If the file name has special constructs in it, | 2749 | /* If the file name has special constructs in it, |
| 2581 | call the corresponding file handler. */ | 2750 | call the corresponding file handler. */ |
| 2582 | handler = Ffind_file_name_handler (abspath, Qfile_directory_p); | 2751 | handler = Ffind_file_name_handler (absname, Qfile_directory_p); |
| 2583 | if (!NILP (handler)) | 2752 | if (!NILP (handler)) |
| 2584 | return call2 (handler, Qfile_directory_p, abspath); | 2753 | return call2 (handler, Qfile_directory_p, absname); |
| 2585 | 2754 | ||
| 2586 | if (stat (XSTRING (abspath)->data, &st) < 0) | 2755 | if (stat (XSTRING (absname)->data, &st) < 0) |
| 2587 | return Qnil; | 2756 | return Qnil; |
| 2588 | return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil; | 2757 | return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil; |
| 2589 | } | 2758 | } |
| @@ -2627,19 +2796,19 @@ This is the sort of file that holds an ordinary stream of data bytes.") | |||
| 2627 | (filename) | 2796 | (filename) |
| 2628 | Lisp_Object filename; | 2797 | Lisp_Object filename; |
| 2629 | { | 2798 | { |
| 2630 | register Lisp_Object abspath; | 2799 | register Lisp_Object absname; |
| 2631 | struct stat st; | 2800 | struct stat st; |
| 2632 | Lisp_Object handler; | 2801 | Lisp_Object handler; |
| 2633 | 2802 | ||
| 2634 | abspath = expand_and_dir_to_file (filename, current_buffer->directory); | 2803 | absname = expand_and_dir_to_file (filename, current_buffer->directory); |
| 2635 | 2804 | ||
| 2636 | /* If the file name has special constructs in it, | 2805 | /* If the file name has special constructs in it, |
| 2637 | call the corresponding file handler. */ | 2806 | call the corresponding file handler. */ |
| 2638 | handler = Ffind_file_name_handler (abspath, Qfile_regular_p); | 2807 | handler = Ffind_file_name_handler (absname, Qfile_regular_p); |
| 2639 | if (!NILP (handler)) | 2808 | if (!NILP (handler)) |
| 2640 | return call2 (handler, Qfile_regular_p, abspath); | 2809 | return call2 (handler, Qfile_regular_p, absname); |
| 2641 | 2810 | ||
| 2642 | if (stat (XSTRING (abspath)->data, &st) < 0) | 2811 | if (stat (XSTRING (absname)->data, &st) < 0) |
| 2643 | return Qnil; | 2812 | return Qnil; |
| 2644 | return (st.st_mode & S_IFMT) == S_IFREG ? Qt : Qnil; | 2813 | return (st.st_mode & S_IFMT) == S_IFREG ? Qt : Qnil; |
| 2645 | } | 2814 | } |
| @@ -2649,24 +2818,24 @@ DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, | |||
| 2649 | (filename) | 2818 | (filename) |
| 2650 | Lisp_Object filename; | 2819 | Lisp_Object filename; |
| 2651 | { | 2820 | { |
| 2652 | Lisp_Object abspath; | 2821 | Lisp_Object absname; |
| 2653 | struct stat st; | 2822 | struct stat st; |
| 2654 | Lisp_Object handler; | 2823 | Lisp_Object handler; |
| 2655 | 2824 | ||
| 2656 | abspath = expand_and_dir_to_file (filename, current_buffer->directory); | 2825 | absname = expand_and_dir_to_file (filename, current_buffer->directory); |
| 2657 | 2826 | ||
| 2658 | /* If the file name has special constructs in it, | 2827 | /* If the file name has special constructs in it, |
| 2659 | call the corresponding file handler. */ | 2828 | call the corresponding file handler. */ |
| 2660 | handler = Ffind_file_name_handler (abspath, Qfile_modes); | 2829 | handler = Ffind_file_name_handler (absname, Qfile_modes); |
| 2661 | if (!NILP (handler)) | 2830 | if (!NILP (handler)) |
| 2662 | return call2 (handler, Qfile_modes, abspath); | 2831 | return call2 (handler, Qfile_modes, absname); |
| 2663 | 2832 | ||
| 2664 | if (stat (XSTRING (abspath)->data, &st) < 0) | 2833 | if (stat (XSTRING (absname)->data, &st) < 0) |
| 2665 | return Qnil; | 2834 | return Qnil; |
| 2666 | #ifdef DOS_NT | 2835 | #ifdef MSDOS |
| 2667 | if (check_executable (XSTRING (abspath)->data)) | 2836 | if (check_executable (XSTRING (absname)->data)) |
| 2668 | st.st_mode |= S_IEXEC; | 2837 | st.st_mode |= S_IEXEC; |
| 2669 | #endif /* DOS_NT */ | 2838 | #endif /* MSDOS */ |
| 2670 | 2839 | ||
| 2671 | return make_number (st.st_mode & 07777); | 2840 | return make_number (st.st_mode & 07777); |
| 2672 | } | 2841 | } |
| @@ -2677,20 +2846,20 @@ Only the 12 low bits of MODE are used.") | |||
| 2677 | (filename, mode) | 2846 | (filename, mode) |
| 2678 | Lisp_Object filename, mode; | 2847 | Lisp_Object filename, mode; |
| 2679 | { | 2848 | { |
| 2680 | Lisp_Object abspath; | 2849 | Lisp_Object absname; |
| 2681 | Lisp_Object handler; | 2850 | Lisp_Object handler; |
| 2682 | 2851 | ||
| 2683 | abspath = Fexpand_file_name (filename, current_buffer->directory); | 2852 | absname = Fexpand_file_name (filename, current_buffer->directory); |
| 2684 | CHECK_NUMBER (mode, 1); | 2853 | CHECK_NUMBER (mode, 1); |
| 2685 | 2854 | ||
| 2686 | /* If the file name has special constructs in it, | 2855 | /* If the file name has special constructs in it, |
| 2687 | call the corresponding file handler. */ | 2856 | call the corresponding file handler. */ |
| 2688 | handler = Ffind_file_name_handler (abspath, Qset_file_modes); | 2857 | handler = Ffind_file_name_handler (absname, Qset_file_modes); |
| 2689 | if (!NILP (handler)) | 2858 | if (!NILP (handler)) |
| 2690 | return call3 (handler, Qset_file_modes, abspath, mode); | 2859 | return call3 (handler, Qset_file_modes, absname, mode); |
| 2691 | 2860 | ||
| 2692 | if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0) | 2861 | if (chmod (XSTRING (absname)->data, XINT (mode)) < 0) |
| 2693 | report_file_error ("Doing chmod", Fcons (abspath, Qnil)); | 2862 | report_file_error ("Doing chmod", Fcons (absname, Qnil)); |
| 2694 | 2863 | ||
| 2695 | return Qnil; | 2864 | return Qnil; |
| 2696 | } | 2865 | } |
| @@ -2703,7 +2872,7 @@ This setting is inherited by subprocesses.") | |||
| 2703 | Lisp_Object mode; | 2872 | Lisp_Object mode; |
| 2704 | { | 2873 | { |
| 2705 | CHECK_NUMBER (mode, 0); | 2874 | CHECK_NUMBER (mode, 0); |
| 2706 | 2875 | ||
| 2707 | umask ((~ XINT (mode)) & 0777); | 2876 | umask ((~ XINT (mode)) & 0777); |
| 2708 | 2877 | ||
| 2709 | return Qnil; | 2878 | return Qnil; |
| @@ -2743,7 +2912,7 @@ otherwise, if FILE2 does not exist, the answer is t.") | |||
| 2743 | (file1, file2) | 2912 | (file1, file2) |
| 2744 | Lisp_Object file1, file2; | 2913 | Lisp_Object file1, file2; |
| 2745 | { | 2914 | { |
| 2746 | Lisp_Object abspath1, abspath2; | 2915 | Lisp_Object absname1, absname2; |
| 2747 | struct stat st; | 2916 | struct stat st; |
| 2748 | int mtime1; | 2917 | int mtime1; |
| 2749 | Lisp_Object handler; | 2918 | Lisp_Object handler; |
| @@ -2752,26 +2921,26 @@ otherwise, if FILE2 does not exist, the answer is t.") | |||
| 2752 | CHECK_STRING (file1, 0); | 2921 | CHECK_STRING (file1, 0); |
| 2753 | CHECK_STRING (file2, 0); | 2922 | CHECK_STRING (file2, 0); |
| 2754 | 2923 | ||
| 2755 | abspath1 = Qnil; | 2924 | absname1 = Qnil; |
| 2756 | GCPRO2 (abspath1, file2); | 2925 | GCPRO2 (absname1, file2); |
| 2757 | abspath1 = expand_and_dir_to_file (file1, current_buffer->directory); | 2926 | absname1 = expand_and_dir_to_file (file1, current_buffer->directory); |
| 2758 | abspath2 = expand_and_dir_to_file (file2, current_buffer->directory); | 2927 | absname2 = expand_and_dir_to_file (file2, current_buffer->directory); |
| 2759 | UNGCPRO; | 2928 | UNGCPRO; |
| 2760 | 2929 | ||
| 2761 | /* If the file name has special constructs in it, | 2930 | /* If the file name has special constructs in it, |
| 2762 | call the corresponding file handler. */ | 2931 | call the corresponding file handler. */ |
| 2763 | handler = Ffind_file_name_handler (abspath1, Qfile_newer_than_file_p); | 2932 | handler = Ffind_file_name_handler (absname1, Qfile_newer_than_file_p); |
| 2764 | if (NILP (handler)) | 2933 | if (NILP (handler)) |
| 2765 | handler = Ffind_file_name_handler (abspath2, Qfile_newer_than_file_p); | 2934 | handler = Ffind_file_name_handler (absname2, Qfile_newer_than_file_p); |
| 2766 | if (!NILP (handler)) | 2935 | if (!NILP (handler)) |
| 2767 | return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2); | 2936 | return call3 (handler, Qfile_newer_than_file_p, absname1, absname2); |
| 2768 | 2937 | ||
| 2769 | if (stat (XSTRING (abspath1)->data, &st) < 0) | 2938 | if (stat (XSTRING (absname1)->data, &st) < 0) |
| 2770 | return Qnil; | 2939 | return Qnil; |
| 2771 | 2940 | ||
| 2772 | mtime1 = st.st_mtime; | 2941 | mtime1 = st.st_mtime; |
| 2773 | 2942 | ||
| 2774 | if (stat (XSTRING (abspath2)->data, &st) < 0) | 2943 | if (stat (XSTRING (absname2)->data, &st) < 0) |
| 2775 | return Qt; | 2944 | return Qt; |
| 2776 | 2945 | ||
| 2777 | return (mtime1 > st.st_mtime) ? Qt : Qnil; | 2946 | return (mtime1 > st.st_mtime) ? Qt : Qnil; |
| @@ -3148,7 +3317,7 @@ and (2) it puts less data in the undo list.") | |||
| 3148 | /* Decode file format */ | 3317 | /* Decode file format */ |
| 3149 | if (inserted > 0) | 3318 | if (inserted > 0) |
| 3150 | { | 3319 | { |
| 3151 | insval = call3 (Qformat_decode, | 3320 | insval = call3 (Qformat_decode, |
| 3152 | Qnil, make_number (inserted), visit); | 3321 | Qnil, make_number (inserted), visit); |
| 3153 | CHECK_NUMBER (insval, 0); | 3322 | CHECK_NUMBER (insval, 0); |
| 3154 | inserted = XFASTINT (insval); | 3323 | inserted = XFASTINT (insval); |
| @@ -3156,7 +3325,7 @@ and (2) it puts less data in the undo list.") | |||
| 3156 | 3325 | ||
| 3157 | if (inserted > 0 && NILP (visit) && total > 0) | 3326 | if (inserted > 0 && NILP (visit) && total > 0) |
| 3158 | signal_after_change (point, 0, inserted); | 3327 | signal_after_change (point, 0, inserted); |
| 3159 | 3328 | ||
| 3160 | if (inserted > 0) | 3329 | if (inserted > 0) |
| 3161 | { | 3330 | { |
| 3162 | p = Vafter_insert_file_functions; | 3331 | p = Vafter_insert_file_functions; |
| @@ -3186,7 +3355,7 @@ static Lisp_Object build_annotations (); | |||
| 3186 | /* If build_annotations switched buffers, switch back to BUF. | 3355 | /* If build_annotations switched buffers, switch back to BUF. |
| 3187 | Kill the temporary buffer that was selected in the meantime. */ | 3356 | Kill the temporary buffer that was selected in the meantime. */ |
| 3188 | 3357 | ||
| 3189 | static Lisp_Object | 3358 | static Lisp_Object |
| 3190 | build_annotations_unwind (buf) | 3359 | build_annotations_unwind (buf) |
| 3191 | Lisp_Object buf; | 3360 | Lisp_Object buf; |
| 3192 | { | 3361 | { |
| @@ -3273,7 +3442,7 @@ to the file, instead of any buffer contents, and END is ignored.") | |||
| 3273 | handler = Ffind_file_name_handler (filename, Qwrite_region); | 3442 | handler = Ffind_file_name_handler (filename, Qwrite_region); |
| 3274 | /* If FILENAME has no handler, see if VISIT has one. */ | 3443 | /* If FILENAME has no handler, see if VISIT has one. */ |
| 3275 | if (NILP (handler) && STRINGP (visit)) | 3444 | if (NILP (handler) && STRINGP (visit)) |
| 3276 | handler = Ffind_file_name_handler (visit, Qwrite_region); | 3445 | handler = Ffind_file_name_handler (visit, Qwrite_region); |
| 3277 | 3446 | ||
| 3278 | if (!NILP (handler)) | 3447 | if (!NILP (handler)) |
| 3279 | { | 3448 | { |
| @@ -3371,8 +3540,8 @@ to the file, instead of any buffer contents, and END is ignored.") | |||
| 3371 | } | 3540 | } |
| 3372 | #else /* not VMS */ | 3541 | #else /* not VMS */ |
| 3373 | #ifdef DOS_NT | 3542 | #ifdef DOS_NT |
| 3374 | desc = open (fn, | 3543 | desc = open (fn, |
| 3375 | O_WRONLY | O_TRUNC | O_CREAT | buffer_file_type, | 3544 | O_WRONLY | O_TRUNC | O_CREAT | buffer_file_type, |
| 3376 | S_IREAD | S_IWRITE); | 3545 | S_IREAD | S_IWRITE); |
| 3377 | #else /* not DOS_NT */ | 3546 | #else /* not DOS_NT */ |
| 3378 | desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666); | 3547 | desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666); |
| @@ -3476,7 +3645,7 @@ to the file, instead of any buffer contents, and END is ignored.") | |||
| 3476 | } | 3645 | } |
| 3477 | #endif | 3646 | #endif |
| 3478 | 3647 | ||
| 3479 | /* Spurious "file has changed on disk" warnings have been | 3648 | /* Spurious "file has changed on disk" warnings have been |
| 3480 | observed on Suns as well. | 3649 | observed on Suns as well. |
| 3481 | It seems that `close' can change the modtime, under nfs. | 3650 | It seems that `close' can change the modtime, under nfs. |
| 3482 | 3651 | ||
| @@ -3882,7 +4051,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer.") | |||
| 3882 | Lisp_Object listfile; | 4051 | Lisp_Object listfile; |
| 3883 | listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil); | 4052 | listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil); |
| 3884 | #ifdef DOS_NT | 4053 | #ifdef DOS_NT |
| 3885 | listdesc = open (XSTRING (listfile)->data, | 4054 | listdesc = open (XSTRING (listfile)->data, |
| 3886 | O_WRONLY | O_TRUNC | O_CREAT | O_TEXT, | 4055 | O_WRONLY | O_TRUNC | O_CREAT | O_TEXT, |
| 3887 | S_IREAD | S_IWRITE); | 4056 | S_IREAD | S_IWRITE); |
| 3888 | #else /* not DOS_NT */ | 4057 | #else /* not DOS_NT */ |
| @@ -3891,7 +4060,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer.") | |||
| 3891 | } | 4060 | } |
| 3892 | else | 4061 | else |
| 3893 | listdesc = -1; | 4062 | listdesc = -1; |
| 3894 | 4063 | ||
| 3895 | /* Arrange to close that file whether or not we get an error. | 4064 | /* Arrange to close that file whether or not we get an error. |
| 3896 | Also reset auto_saving to 0. */ | 4065 | Also reset auto_saving to 0. */ |
| 3897 | record_unwind_protect (do_auto_save_unwind, make_number (listdesc)); | 4066 | record_unwind_protect (do_auto_save_unwind, make_number (listdesc)); |
| @@ -3908,7 +4077,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer.") | |||
| 3908 | { | 4077 | { |
| 3909 | buf = XCONS (XCONS (tail)->car)->cdr; | 4078 | buf = XCONS (XCONS (tail)->car)->cdr; |
| 3910 | b = XBUFFER (buf); | 4079 | b = XBUFFER (buf); |
| 3911 | 4080 | ||
| 3912 | /* Record all the buffers that have auto save mode | 4081 | /* Record all the buffers that have auto save mode |
| 3913 | in the special file that lists them. For each of these buffers, | 4082 | in the special file that lists them. For each of these buffers, |
| 3914 | Record visited name (if any) and auto save name. */ | 4083 | Record visited name (if any) and auto save name. */ |
| @@ -4179,6 +4348,10 @@ DIR defaults to current buffer's directory default.") | |||
| 4179 | 4348 | ||
| 4180 | /* If dir starts with user's homedir, change that to ~. */ | 4349 | /* If dir starts with user's homedir, change that to ~. */ |
| 4181 | homedir = (char *) egetenv ("HOME"); | 4350 | homedir = (char *) egetenv ("HOME"); |
| 4351 | #ifdef DOS_NT | ||
| 4352 | homedir = strcpy (alloca (strlen (homedir) + 1), homedir); | ||
| 4353 | CORRECT_DIR_SEPS (homedir); | ||
| 4354 | #endif | ||
| 4182 | if (homedir != 0 | 4355 | if (homedir != 0 |
| 4183 | && STRINGP (dir) | 4356 | && STRINGP (dir) |
| 4184 | && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir)) | 4357 | && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir)) |
| @@ -4372,7 +4545,7 @@ syms_of_fileio () | |||
| 4372 | 4545 | ||
| 4373 | Qfile_error = intern ("file-error"); | 4546 | Qfile_error = intern ("file-error"); |
| 4374 | staticpro (&Qfile_error); | 4547 | staticpro (&Qfile_error); |
| 4375 | Qfile_already_exists = intern("file-already-exists"); | 4548 | Qfile_already_exists = intern ("file-already-exists"); |
| 4376 | staticpro (&Qfile_already_exists); | 4549 | staticpro (&Qfile_already_exists); |
| 4377 | 4550 | ||
| 4378 | #ifdef DOS_NT | 4551 | #ifdef DOS_NT |
| @@ -4415,6 +4588,14 @@ same format as a regular save would use."); | |||
| 4415 | nil means use format `var'. This variable is meaningful only on VMS."); | 4588 | nil means use format `var'. This variable is meaningful only on VMS."); |
| 4416 | vms_stmlf_recfm = 0; | 4589 | vms_stmlf_recfm = 0; |
| 4417 | 4590 | ||
| 4591 | DEFVAR_LISP ("directory-sep-char", &Vdirectory_sep_char, | ||
| 4592 | "Directory separator character for built-in functions that return file names.\n\ | ||
| 4593 | The value should be either ?/ or ?\\ (any other value is treated as ?\\).\n\ | ||
| 4594 | This variable affects the built-in functions only on Windows,\n\ | ||
| 4595 | on other platforms, it is initialized so that Lisp code can find out\n\ | ||
| 4596 | what the normal separator is."); | ||
| 4597 | Vdirectory_sep_char = '/'; | ||
| 4598 | |||
| 4418 | DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist, | 4599 | DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist, |
| 4419 | "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\ | 4600 | "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\ |
| 4420 | If a file name matches REGEXP, then all I/O on that file is done by calling\n\ | 4601 | If a file name matches REGEXP, then all I/O on that file is done by calling\n\ |