diff options
Diffstat (limited to 'src/dired.c')
| -rw-r--r-- | src/dired.c | 205 |
1 files changed, 90 insertions, 115 deletions
diff --git a/src/dired.c b/src/dired.c index 4986f845101..3530b74ecb4 100644 --- a/src/dired.c +++ b/src/dired.c | |||
| @@ -31,44 +31,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 31 | #include <errno.h> | 31 | #include <errno.h> |
| 32 | #include <unistd.h> | 32 | #include <unistd.h> |
| 33 | 33 | ||
| 34 | /* The d_nameln member of a struct dirent includes the '\0' character | ||
| 35 | on some systems, but not on others. What's worse, you can't tell | ||
| 36 | at compile-time which one it will be, since it really depends on | ||
| 37 | the sort of system providing the filesystem you're reading from, | ||
| 38 | not the system you are running on. Paul Eggert | ||
| 39 | <eggert@bi.twinsun.com> says this occurs when Emacs is running on a | ||
| 40 | SunOS 4.1.2 host, reading a directory that is remote-mounted from a | ||
| 41 | Solaris 2.1 host and is in a native Solaris 2.1 filesystem. | ||
| 42 | |||
| 43 | Since applying strlen to the name always works, we'll just do that. */ | ||
| 44 | #define NAMLEN(p) strlen (p->d_name) | ||
| 45 | |||
| 46 | #ifdef HAVE_DIRENT_H | ||
| 47 | |||
| 48 | #include <dirent.h> | 34 | #include <dirent.h> |
| 49 | #define DIRENTRY struct dirent | ||
| 50 | |||
| 51 | #else /* not HAVE_DIRENT_H */ | ||
| 52 | |||
| 53 | #include <sys/dir.h> | ||
| 54 | #include <sys/stat.h> | ||
| 55 | |||
| 56 | #define DIRENTRY struct direct | ||
| 57 | |||
| 58 | extern DIR *opendir (char *); | ||
| 59 | extern struct direct *readdir (DIR *); | ||
| 60 | |||
| 61 | #endif /* HAVE_DIRENT_H */ | ||
| 62 | |||
| 63 | #include <filemode.h> | 35 | #include <filemode.h> |
| 64 | #include <stat-time.h> | 36 | #include <stat-time.h> |
| 65 | 37 | ||
| 66 | #ifdef MSDOS | ||
| 67 | #define DIRENTRY_NONEMPTY(p) ((p)->d_name[0] != 0) | ||
| 68 | #else | ||
| 69 | #define DIRENTRY_NONEMPTY(p) ((p)->d_ino) | ||
| 70 | #endif | ||
| 71 | |||
| 72 | #include "lisp.h" | 38 | #include "lisp.h" |
| 73 | #include "systime.h" | 39 | #include "systime.h" |
| 74 | #include "character.h" | 40 | #include "character.h" |
| @@ -88,6 +54,17 @@ static Lisp_Object Qfile_attributes_lessp; | |||
| 88 | 54 | ||
| 89 | static ptrdiff_t scmp (const char *, const char *, ptrdiff_t); | 55 | static ptrdiff_t scmp (const char *, const char *, ptrdiff_t); |
| 90 | 56 | ||
| 57 | /* Return the number of bytes in DP's name. */ | ||
| 58 | static ptrdiff_t | ||
| 59 | dirent_namelen (struct dirent *dp) | ||
| 60 | { | ||
| 61 | #ifdef _D_EXACT_NAMLEN | ||
| 62 | return _D_EXACT_NAMLEN (dp); | ||
| 63 | #else | ||
| 64 | return strlen (dp->d_name); | ||
| 65 | #endif | ||
| 66 | } | ||
| 67 | |||
| 91 | #ifdef WINDOWSNT | 68 | #ifdef WINDOWSNT |
| 92 | Lisp_Object | 69 | Lisp_Object |
| 93 | directory_files_internal_w32_unwind (Lisp_Object arg) | 70 | directory_files_internal_w32_unwind (Lisp_Object arg) |
| @@ -124,7 +101,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 124 | bool needsep = 0; | 101 | bool needsep = 0; |
| 125 | ptrdiff_t count = SPECPDL_INDEX (); | 102 | ptrdiff_t count = SPECPDL_INDEX (); |
| 126 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; | 103 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; |
| 127 | DIRENTRY *dp; | 104 | struct dirent *dp; |
| 128 | #ifdef WINDOWSNT | 105 | #ifdef WINDOWSNT |
| 129 | Lisp_Object w32_save = Qnil; | 106 | Lisp_Object w32_save = Qnil; |
| 130 | #endif | 107 | #endif |
| @@ -209,6 +186,11 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 209 | /* Loop reading blocks until EOF or error. */ | 186 | /* Loop reading blocks until EOF or error. */ |
| 210 | for (;;) | 187 | for (;;) |
| 211 | { | 188 | { |
| 189 | ptrdiff_t len; | ||
| 190 | bool wanted = 0; | ||
| 191 | Lisp_Object name, finalname; | ||
| 192 | struct gcpro gcpro1, gcpro2; | ||
| 193 | |||
| 212 | errno = 0; | 194 | errno = 0; |
| 213 | dp = readdir (d); | 195 | dp = readdir (d); |
| 214 | 196 | ||
| @@ -225,89 +207,81 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 225 | if (dp == NULL) | 207 | if (dp == NULL) |
| 226 | break; | 208 | break; |
| 227 | 209 | ||
| 228 | if (DIRENTRY_NONEMPTY (dp)) | 210 | len = dirent_namelen (dp); |
| 211 | name = finalname = make_unibyte_string (dp->d_name, len); | ||
| 212 | GCPRO2 (finalname, name); | ||
| 213 | |||
| 214 | /* Note: DECODE_FILE can GC; it should protect its argument, | ||
| 215 | though. */ | ||
| 216 | name = DECODE_FILE (name); | ||
| 217 | len = SBYTES (name); | ||
| 218 | |||
| 219 | /* Now that we have unwind_protect in place, we might as well | ||
| 220 | allow matching to be interrupted. */ | ||
| 221 | immediate_quit = 1; | ||
| 222 | QUIT; | ||
| 223 | |||
| 224 | if (NILP (match) | ||
| 225 | || (0 <= re_search (bufp, SSDATA (name), len, 0, len, 0))) | ||
| 226 | wanted = 1; | ||
| 227 | |||
| 228 | immediate_quit = 0; | ||
| 229 | |||
| 230 | if (wanted) | ||
| 229 | { | 231 | { |
| 230 | ptrdiff_t len; | 232 | if (!NILP (full)) |
| 231 | bool wanted = 0; | 233 | { |
| 232 | Lisp_Object name, finalname; | 234 | Lisp_Object fullname; |
| 233 | struct gcpro gcpro1, gcpro2; | 235 | ptrdiff_t nbytes = len + directory_nbytes + needsep; |
| 236 | ptrdiff_t nchars; | ||
| 234 | 237 | ||
| 235 | len = NAMLEN (dp); | 238 | fullname = make_uninit_multibyte_string (nbytes, nbytes); |
| 236 | name = finalname = make_unibyte_string (dp->d_name, len); | 239 | memcpy (SDATA (fullname), SDATA (directory), |
| 237 | GCPRO2 (finalname, name); | 240 | directory_nbytes); |
| 238 | 241 | ||
| 239 | /* Note: DECODE_FILE can GC; it should protect its argument, | 242 | if (needsep) |
| 240 | though. */ | 243 | SSET (fullname, directory_nbytes, DIRECTORY_SEP); |
| 241 | name = DECODE_FILE (name); | ||
| 242 | len = SBYTES (name); | ||
| 243 | 244 | ||
| 244 | /* Now that we have unwind_protect in place, we might as well | 245 | memcpy (SDATA (fullname) + directory_nbytes + needsep, |
| 245 | allow matching to be interrupted. */ | 246 | SDATA (name), len); |
| 246 | immediate_quit = 1; | ||
| 247 | QUIT; | ||
| 248 | 247 | ||
| 249 | if (NILP (match) | 248 | nchars = chars_in_text (SDATA (fullname), nbytes); |
| 250 | || (0 <= re_search (bufp, SSDATA (name), len, 0, len, 0))) | ||
| 251 | wanted = 1; | ||
| 252 | 249 | ||
| 253 | immediate_quit = 0; | 250 | /* Some bug somewhere. */ |
| 251 | if (nchars > nbytes) | ||
| 252 | emacs_abort (); | ||
| 254 | 253 | ||
| 255 | if (wanted) | 254 | STRING_SET_CHARS (fullname, nchars); |
| 256 | { | 255 | if (nchars == nbytes) |
| 257 | if (!NILP (full)) | 256 | STRING_SET_UNIBYTE (fullname); |
| 258 | { | 257 | |
| 259 | Lisp_Object fullname; | 258 | finalname = fullname; |
| 260 | ptrdiff_t nbytes = len + directory_nbytes + needsep; | ||
| 261 | ptrdiff_t nchars; | ||
| 262 | |||
| 263 | fullname = make_uninit_multibyte_string (nbytes, nbytes); | ||
| 264 | memcpy (SDATA (fullname), SDATA (directory), | ||
| 265 | directory_nbytes); | ||
| 266 | |||
| 267 | if (needsep) | ||
| 268 | SSET (fullname, directory_nbytes, DIRECTORY_SEP); | ||
| 269 | |||
| 270 | memcpy (SDATA (fullname) + directory_nbytes + needsep, | ||
| 271 | SDATA (name), len); | ||
| 272 | |||
| 273 | nchars = chars_in_text (SDATA (fullname), nbytes); | ||
| 274 | |||
| 275 | /* Some bug somewhere. */ | ||
| 276 | if (nchars > nbytes) | ||
| 277 | emacs_abort (); | ||
| 278 | |||
| 279 | STRING_SET_CHARS (fullname, nchars); | ||
| 280 | if (nchars == nbytes) | ||
| 281 | STRING_SET_UNIBYTE (fullname); | ||
| 282 | |||
| 283 | finalname = fullname; | ||
| 284 | } | ||
| 285 | else | ||
| 286 | finalname = name; | ||
| 287 | |||
| 288 | if (attrs) | ||
| 289 | { | ||
| 290 | /* Construct an expanded filename for the directory entry. | ||
| 291 | Use the decoded names for input to Ffile_attributes. */ | ||
| 292 | Lisp_Object decoded_fullname, fileattrs; | ||
| 293 | struct gcpro gcpro1, gcpro2; | ||
| 294 | |||
| 295 | decoded_fullname = fileattrs = Qnil; | ||
| 296 | GCPRO2 (decoded_fullname, fileattrs); | ||
| 297 | |||
| 298 | /* Both Fexpand_file_name and Ffile_attributes can GC. */ | ||
| 299 | decoded_fullname = Fexpand_file_name (name, directory); | ||
| 300 | fileattrs = Ffile_attributes (decoded_fullname, id_format); | ||
| 301 | |||
| 302 | list = Fcons (Fcons (finalname, fileattrs), list); | ||
| 303 | UNGCPRO; | ||
| 304 | } | ||
| 305 | else | ||
| 306 | list = Fcons (finalname, list); | ||
| 307 | } | 259 | } |
| 260 | else | ||
| 261 | finalname = name; | ||
| 308 | 262 | ||
| 309 | UNGCPRO; | 263 | if (attrs) |
| 264 | { | ||
| 265 | /* Construct an expanded filename for the directory entry. | ||
| 266 | Use the decoded names for input to Ffile_attributes. */ | ||
| 267 | Lisp_Object decoded_fullname, fileattrs; | ||
| 268 | struct gcpro gcpro1, gcpro2; | ||
| 269 | |||
| 270 | decoded_fullname = fileattrs = Qnil; | ||
| 271 | GCPRO2 (decoded_fullname, fileattrs); | ||
| 272 | |||
| 273 | /* Both Fexpand_file_name and Ffile_attributes can GC. */ | ||
| 274 | decoded_fullname = Fexpand_file_name (name, directory); | ||
| 275 | fileattrs = Ffile_attributes (decoded_fullname, id_format); | ||
| 276 | |||
| 277 | list = Fcons (Fcons (finalname, fileattrs), list); | ||
| 278 | UNGCPRO; | ||
| 279 | } | ||
| 280 | else | ||
| 281 | list = Fcons (finalname, list); | ||
| 310 | } | 282 | } |
| 283 | |||
| 284 | UNGCPRO; | ||
| 311 | } | 285 | } |
| 312 | 286 | ||
| 313 | block_input (); | 287 | block_input (); |
| @@ -442,7 +416,8 @@ These are all file names in directory DIRECTORY which begin with FILE. */) | |||
| 442 | return file_name_completion (file, directory, 1, Qnil); | 416 | return file_name_completion (file, directory, 1, Qnil); |
| 443 | } | 417 | } |
| 444 | 418 | ||
| 445 | static int file_name_completion_stat (Lisp_Object dirname, DIRENTRY *dp, struct stat *st_addr); | 419 | static int file_name_completion_stat (Lisp_Object dirname, struct dirent *dp, |
| 420 | struct stat *st_addr); | ||
| 446 | static Lisp_Object Qdefault_directory; | 421 | static Lisp_Object Qdefault_directory; |
| 447 | 422 | ||
| 448 | static Lisp_Object | 423 | static Lisp_Object |
| @@ -499,7 +474,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, | |||
| 499 | /* (att3b compiler bug requires do a null comparison this way) */ | 474 | /* (att3b compiler bug requires do a null comparison this way) */ |
| 500 | while (1) | 475 | while (1) |
| 501 | { | 476 | { |
| 502 | DIRENTRY *dp; | 477 | struct dirent *dp; |
| 503 | ptrdiff_t len; | 478 | ptrdiff_t len; |
| 504 | bool canexclude = 0; | 479 | bool canexclude = 0; |
| 505 | 480 | ||
| @@ -517,11 +492,10 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, | |||
| 517 | 492 | ||
| 518 | if (!dp) break; | 493 | if (!dp) break; |
| 519 | 494 | ||
| 520 | len = NAMLEN (dp); | 495 | len = dirent_namelen (dp); |
| 521 | 496 | ||
| 522 | QUIT; | 497 | QUIT; |
| 523 | if (! DIRENTRY_NONEMPTY (dp) | 498 | if (len < SCHARS (encoded_file) |
| 524 | || len < SCHARS (encoded_file) | ||
| 525 | || 0 <= scmp (dp->d_name, SSDATA (encoded_file), | 499 | || 0 <= scmp (dp->d_name, SSDATA (encoded_file), |
| 526 | SCHARS (encoded_file))) | 500 | SCHARS (encoded_file))) |
| 527 | continue; | 501 | continue; |
| @@ -806,9 +780,10 @@ scmp (const char *s1, const char *s2, ptrdiff_t len) | |||
| 806 | } | 780 | } |
| 807 | 781 | ||
| 808 | static int | 782 | static int |
| 809 | file_name_completion_stat (Lisp_Object dirname, DIRENTRY *dp, struct stat *st_addr) | 783 | file_name_completion_stat (Lisp_Object dirname, struct dirent *dp, |
| 784 | struct stat *st_addr) | ||
| 810 | { | 785 | { |
| 811 | ptrdiff_t len = NAMLEN (dp); | 786 | ptrdiff_t len = dirent_namelen (dp); |
| 812 | ptrdiff_t pos = SCHARS (dirname); | 787 | ptrdiff_t pos = SCHARS (dirname); |
| 813 | int value; | 788 | int value; |
| 814 | USE_SAFE_ALLOCA; | 789 | USE_SAFE_ALLOCA; |