aboutsummaryrefslogtreecommitdiffstats
path: root/src/fileio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fileio.c')
-rw-r--r--src/fileio.c179
1 files changed, 88 insertions, 91 deletions
diff --git a/src/fileio.c b/src/fileio.c
index 60d9c46b6eb..e1da0fc6918 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -1016,7 +1016,7 @@ probably use `make-temp-file' instead, except in three circumstances:
1016DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0, 1016DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
1017 doc: /* Convert filename NAME to absolute, and canonicalize it. 1017 doc: /* Convert filename NAME to absolute, and canonicalize it.
1018Second arg DEFAULT-DIRECTORY is directory to start with if NAME is relative 1018Second arg DEFAULT-DIRECTORY is directory to start with if NAME is relative
1019 (does not start with slash); if DEFAULT-DIRECTORY is nil or missing, 1019\(does not start with slash); if DEFAULT-DIRECTORY is nil or missing,
1020the current buffer's value of default-directory is used. 1020the current buffer's value of default-directory is used.
1021File name components that are `.' are removed, and 1021File name components that are `.' are removed, and
1022so are file name components followed by `..', along with the `..' itself; 1022so are file name components followed by `..', along with the `..' itself;
@@ -1466,7 +1466,7 @@ See also the function `substitute-in-file-name'. */)
1466 indirectly by prepending newdir to nm if necessary, and using 1466 indirectly by prepending newdir to nm if necessary, and using
1467 cwd (or the wd of newdir's drive) as the new newdir. */ 1467 cwd (or the wd of newdir's drive) as the new newdir. */
1468 1468
1469 if (IS_DRIVE (newdir[0]) && newdir[1] == ':') 1469 if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1]))
1470 { 1470 {
1471 drive = newdir[0]; 1471 drive = newdir[0];
1472 newdir += 2; 1472 newdir += 2;
@@ -1489,7 +1489,7 @@ See also the function `substitute-in-file-name'. */)
1489 } 1489 }
1490 1490
1491 /* Strip off drive name from prefix, if present. */ 1491 /* Strip off drive name from prefix, if present. */
1492 if (IS_DRIVE (newdir[0]) && newdir[1] == ':') 1492 if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1]))
1493 { 1493 {
1494 drive = newdir[0]; 1494 drive = newdir[0];
1495 newdir += 2; 1495 newdir += 2;
@@ -1723,7 +1723,7 @@ See also the function `substitute-in-file-name'. */)
1723DEAFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0, 1723DEAFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
1724 "Convert FILENAME to absolute, and canonicalize it.\n\ 1724 "Convert FILENAME to absolute, and canonicalize it.\n\
1725Second arg DEFAULT is directory to start with if FILENAME is relative\n\ 1725Second arg DEFAULT is directory to start with if FILENAME is relative\n\
1726 (does not start with slash); if DEFAULT is nil or missing,\n\ 1726\(does not start with slash); if DEFAULT is nil or missing,\n\
1727the current buffer's value of default-directory is used.\n\ 1727the current buffer's value of default-directory is used.\n\
1728Filenames containing `.' or `..' as components are simplified;\n\ 1728Filenames containing `.' or `..' as components are simplified;\n\
1729initial `~/' expands to your home directory.\n\ 1729initial `~/' expands to your home directory.\n\
@@ -2042,6 +2042,75 @@ See also the function `substitute-in-file-name'.")
2042} 2042}
2043#endif 2043#endif
2044 2044
2045/* If /~ or // appears, discard everything through first slash. */
2046static int
2047file_name_absolute_p (filename)
2048 const unsigned char *filename;
2049{
2050 return
2051 (IS_DIRECTORY_SEP (*filename) || *filename == '~'
2052#ifdef VMS
2053 /* ??? This criterion is probably wrong for '<'. */
2054 || index (filename, ':') || index (filename, '<')
2055 || (*filename == '[' && (filename[1] != '-'
2056 || (filename[2] != '.' && filename[2] != ']'))
2057 && filename[1] != '.')
2058#endif /* VMS */
2059#ifdef DOS_NT
2060 || (IS_DRIVE (*filename) && IS_DEVICE_SEP (filename[1])
2061 && IS_DIRECTORY_SEP (filename[2]))
2062#endif
2063 );
2064}
2065
2066static unsigned char *
2067search_embedded_absfilename (nm, endp)
2068 unsigned char *nm, *endp;
2069{
2070 unsigned char *p, *s;
2071
2072 for (p = nm + 1; p < endp; p++)
2073 {
2074 if ((0
2075#ifdef VMS
2076 || p[-1] == ':' || p[-1] == ']' || p[-1] == '>'
2077#endif /* VMS */
2078 || IS_DIRECTORY_SEP (p[-1]))
2079 && file_name_absolute_p (p)
2080#if defined (APOLLO) || defined (WINDOWSNT) || defined(CYGWIN)
2081 /* // at start of file name is meaningful in Apollo,
2082 WindowsNT and Cygwin systems. */
2083 && !(IS_DIRECTORY_SEP (p[0]) && p - 1 == nm)
2084#endif /* not (APOLLO || WINDOWSNT || CYGWIN) */
2085 )
2086 {
2087 for (s = p; *s && (!IS_DIRECTORY_SEP (*s)
2088#ifdef VMS
2089 && *s != ':'
2090#endif /* VMS */
2091 ); s++);
2092 if (p[0] == '~' && s > p + 1) /* we've got "/~something/" */
2093 {
2094 unsigned char *o = alloca (s - p + 1);
2095 struct passwd *pw;
2096 bcopy (p, o, s - p);
2097 o [s - p] = 0;
2098
2099 /* If we have ~user and `user' exists, discard
2100 everything up to ~. But if `user' does not exist, leave
2101 ~user alone, it might be a literal file name. */
2102 if ((pw = getpwnam (o + 1)))
2103 return p;
2104 else
2105 xfree (pw);
2106 }
2107 else
2108 return p;
2109 }
2110 }
2111 return NULL;
2112}
2113
2045DEFUN ("substitute-in-file-name", Fsubstitute_in_file_name, 2114DEFUN ("substitute-in-file-name", Fsubstitute_in_file_name,
2046 Ssubstitute_in_file_name, 1, 1, 0, 2115 Ssubstitute_in_file_name, 1, 1, 0,
2047 doc: /* Substitute environment variables referred to in FILENAME. 2116 doc: /* Substitute environment variables referred to in FILENAME.
@@ -2063,7 +2132,6 @@ duplicates what `expand-file-name' does. */)
2063 int total = 0; 2132 int total = 0;
2064 int substituted = 0; 2133 int substituted = 0;
2065 unsigned char *xnm; 2134 unsigned char *xnm;
2066 struct passwd *pw;
2067 Lisp_Object handler; 2135 Lisp_Object handler;
2068 2136
2069 CHECK_STRING (filename); 2137 CHECK_STRING (filename);
@@ -2083,61 +2151,17 @@ duplicates what `expand-file-name' does. */)
2083 endp = nm + SBYTES (filename); 2151 endp = nm + SBYTES (filename);
2084 2152
2085 /* If /~ or // appears, discard everything through first slash. */ 2153 /* If /~ or // appears, discard everything through first slash. */
2086 2154 p = search_embedded_absfilename (nm, endp);
2087 for (p = nm; p != endp; p++) 2155 if (p)
2088 { 2156 /* Start over with the new string, so we check the file-name-handler
2089 if ((p[0] == '~' 2157 again. Important with filenames like "/home/foo//:/hello///there"
2090#if defined (APOLLO) || defined (WINDOWSNT) || defined(CYGWIN) 2158 which whould substitute to "/:/hello///there" rather than "/there". */
2091 /* // at start of file name is meaningful in Apollo, 2159 return Fsubstitute_in_file_name
2092 WindowsNT and Cygwin systems. */ 2160 (make_specified_string (p, -1, endp - p,
2093 || (IS_DIRECTORY_SEP (p[0]) && p - 1 != nm) 2161 STRING_MULTIBYTE (filename)));
2094#else /* not (APOLLO || WINDOWSNT || CYGWIN) */
2095 || IS_DIRECTORY_SEP (p[0])
2096#endif /* not (APOLLO || WINDOWSNT || CYGWIN) */
2097 )
2098 && p != nm
2099 && (0
2100#ifdef VMS
2101 || p[-1] == ':' || p[-1] == ']' || p[-1] == '>'
2102#endif /* VMS */
2103 || IS_DIRECTORY_SEP (p[-1])))
2104 {
2105 for (s = p; *s && (!IS_DIRECTORY_SEP (*s)
2106#ifdef VMS
2107 && *s != ':'
2108#endif /* VMS */
2109 ); s++);
2110 if (p[0] == '~' && s > p + 1) /* we've got "/~something/" */
2111 {
2112 o = (unsigned char *) alloca (s - p + 1);
2113 bcopy ((char *) p, o, s - p);
2114 o [s - p] = 0;
2115
2116 pw = (struct passwd *) getpwnam (o + 1);
2117 }
2118 /* If we have ~/ or ~user and `user' exists, discard
2119 everything up to ~. But if `user' does not exist, leave
2120 ~user alone, it might be a literal file name. */
2121 if (IS_DIRECTORY_SEP (p[0]) || s == p + 1 || pw)
2122 {
2123 nm = p;
2124 substituted = 1;
2125 }
2126 }
2127#ifdef DOS_NT
2128 /* see comment in expand-file-name about drive specifiers */
2129 else if (IS_DRIVE (p[0]) && p[1] == ':'
2130 && p > nm && IS_DIRECTORY_SEP (p[-1]))
2131 {
2132 nm = p;
2133 substituted = 1;
2134 }
2135#endif /* DOS_NT */
2136 }
2137 2162
2138#ifdef VMS 2163#ifdef VMS
2139 return make_specified_string (nm, -1, strlen (nm), 2164 return filename;
2140 STRING_MULTIBYTE (filename));
2141#else 2165#else
2142 2166
2143 /* See if any variables are substituted into the string 2167 /* See if any variables are substituted into the string
@@ -2263,22 +2287,11 @@ duplicates what `expand-file-name' does. */)
2263 *x = 0; 2287 *x = 0;
2264 2288
2265 /* If /~ or // appears, discard everything through first slash. */ 2289 /* If /~ or // appears, discard everything through first slash. */
2266 2290 while ((p = search_embedded_absfilename (xnm, x)))
2267 for (p = xnm; p != x; p++) 2291 /* This time we do not start over because we've already expanded envvars
2268 if ((p[0] == '~' 2292 and replaced $$ with $. Maybe we should start over as well, but we'd
2269#if defined (APOLLO) || defined (WINDOWSNT) || defined(CYGWIN) 2293 need to quote some $ to $$ first. */
2270 || (IS_DIRECTORY_SEP (p[0]) && p - 1 != xnm) 2294 xnm = p;
2271#else /* not (APOLLO || WINDOWSNT || CYGWIN) */
2272 || IS_DIRECTORY_SEP (p[0])
2273#endif /* not (APOLLO || WINDOWSNT || CYGWIN) */
2274 )
2275 && p != xnm && IS_DIRECTORY_SEP (p[-1]))
2276 xnm = p;
2277#ifdef DOS_NT
2278 else if (IS_DRIVE (p[0]) && p[1] == ':'
2279 && p > xnm && IS_DIRECTORY_SEP (p[-1]))
2280 xnm = p;
2281#endif
2282 2295
2283 return make_specified_string (xnm, -1, x - xnm, STRING_MULTIBYTE (filename)); 2296 return make_specified_string (xnm, -1, x - xnm, STRING_MULTIBYTE (filename));
2284 2297
@@ -2961,24 +2974,8 @@ On Unix, this is a name starting with a `/' or a `~'. */)
2961 (filename) 2974 (filename)
2962 Lisp_Object filename; 2975 Lisp_Object filename;
2963{ 2976{
2964 const unsigned char *ptr;
2965
2966 CHECK_STRING (filename); 2977 CHECK_STRING (filename);
2967 ptr = SDATA (filename); 2978 return file_name_absolute_p (SDATA (filename)) ? Qt : Qnil;
2968 if (IS_DIRECTORY_SEP (*ptr) || *ptr == '~'
2969#ifdef VMS
2970/* ??? This criterion is probably wrong for '<'. */
2971 || index (ptr, ':') || index (ptr, '<')
2972 || (*ptr == '[' && (ptr[1] != '-' || (ptr[2] != '.' && ptr[2] != ']'))
2973 && ptr[1] != '.')
2974#endif /* VMS */
2975#ifdef DOS_NT
2976 || (IS_DRIVE (*ptr) && ptr[1] == ':' && IS_DIRECTORY_SEP (ptr[2]))
2977#endif
2978 )
2979 return Qt;
2980 else
2981 return Qnil;
2982} 2979}
2983 2980
2984/* Return nonzero if file FILENAME exists and can be executed. */ 2981/* Return nonzero if file FILENAME exists and can be executed. */