diff options
| author | Paul Eggert | 2019-09-16 13:54:57 -0700 |
|---|---|---|
| committer | Paul Eggert | 2019-09-16 13:55:23 -0700 |
| commit | 2335704fccc2a5088c864bea1f10b4f0ef788e6b (patch) | |
| tree | 98284d464e2143906cb2f9650400b0db85114bb8 /src | |
| parent | 1a84d8fba4b526f7c8f240b8163e66714a41cca6 (diff) | |
| download | emacs-2335704fccc2a5088c864bea1f10b4f0ef788e6b.tar.gz emacs-2335704fccc2a5088c864bea1f10b4f0ef788e6b.zip | |
directory-files cleanup and speed tweaking
* src/dired.c (directory_files_internal):
Check ‘match’ before doing anything heavyweight.
Move decls closer to use.
Remove obsolete comments about GC.
No need to encode ‘directory’ or to call multibyte_chars_in_text.
Remove no-longer-needed bug check.
Skip finalname construction if file_attributes fails.
Diffstat (limited to 'src')
| -rw-r--r-- | src/dired.c | 129 |
1 files changed, 49 insertions, 80 deletions
diff --git a/src/dired.c b/src/dired.c index cec79ab46be..5fc6ccd3ead 100644 --- a/src/dired.c +++ b/src/dired.c | |||
| @@ -167,28 +167,19 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 167 | Lisp_Object match, Lisp_Object nosort, bool attrs, | 167 | Lisp_Object match, Lisp_Object nosort, bool attrs, |
| 168 | Lisp_Object id_format) | 168 | Lisp_Object id_format) |
| 169 | { | 169 | { |
| 170 | ptrdiff_t directory_nbytes; | 170 | if (!NILP (match)) |
| 171 | Lisp_Object list, dirfilename, encoded_directory; | 171 | CHECK_STRING (match); |
| 172 | bool needsep = 0; | ||
| 173 | ptrdiff_t count = SPECPDL_INDEX (); | ||
| 174 | #ifdef WINDOWSNT | ||
| 175 | Lisp_Object w32_save = Qnil; | ||
| 176 | #endif | ||
| 177 | 172 | ||
| 178 | /* Don't let the compiler optimize away all copies of DIRECTORY, | 173 | /* Don't let the compiler optimize away all copies of DIRECTORY, |
| 179 | which would break GC; see Bug#16986. */ | 174 | which would break GC; see Bug#16986. */ |
| 180 | Lisp_Object volatile directory_volatile = directory; | 175 | Lisp_Object volatile directory_volatile = directory; |
| 181 | 176 | ||
| 182 | /* Because of file name handlers, these functions might call | 177 | Lisp_Object dirfilename = Fdirectory_file_name (directory); |
| 183 | Ffuncall, and cause a GC. */ | ||
| 184 | list = encoded_directory = dirfilename = Qnil; | ||
| 185 | dirfilename = Fdirectory_file_name (directory); | ||
| 186 | 178 | ||
| 187 | /* Note: ENCODE_FILE and DECODE_FILE can GC because they can run | 179 | /* Note: ENCODE_FILE and DECODE_FILE can GC because they can run |
| 188 | run_pre_post_conversion_on_str which calls Lisp directly and | 180 | run_pre_post_conversion_on_str which calls Lisp directly and |
| 189 | indirectly. */ | 181 | indirectly. */ |
| 190 | Lisp_Object encoded_dirfilename = ENCODE_FILE (dirfilename); | 182 | Lisp_Object encoded_dirfilename = ENCODE_FILE (dirfilename); |
| 191 | encoded_directory = ENCODE_FILE (directory); | ||
| 192 | 183 | ||
| 193 | int fd; | 184 | int fd; |
| 194 | DIR *d = open_directory (dirfilename, encoded_dirfilename, &fd); | 185 | DIR *d = open_directory (dirfilename, encoded_dirfilename, &fd); |
| @@ -196,9 +187,11 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 196 | /* Unfortunately, we can now invoke expand-file-name and | 187 | /* Unfortunately, we can now invoke expand-file-name and |
| 197 | file-attributes on filenames, both of which can throw, so we must | 188 | file-attributes on filenames, both of which can throw, so we must |
| 198 | do a proper unwind-protect. */ | 189 | do a proper unwind-protect. */ |
| 190 | ptrdiff_t count = SPECPDL_INDEX (); | ||
| 199 | record_unwind_protect_ptr (directory_files_internal_unwind, d); | 191 | record_unwind_protect_ptr (directory_files_internal_unwind, d); |
| 200 | 192 | ||
| 201 | #ifdef WINDOWSNT | 193 | #ifdef WINDOWSNT |
| 194 | Lisp_Object w32_save = Qnil; | ||
| 202 | if (attrs) | 195 | if (attrs) |
| 203 | { | 196 | { |
| 204 | /* Do this only once to avoid doing it (in w32.c:stat) for each | 197 | /* Do this only once to avoid doing it (in w32.c:stat) for each |
| @@ -218,89 +211,63 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 218 | } | 211 | } |
| 219 | #endif | 212 | #endif |
| 220 | 213 | ||
| 221 | directory_nbytes = SBYTES (directory); | 214 | ptrdiff_t directory_nbytes = SBYTES (directory); |
| 222 | re_match_object = Qt; | 215 | re_match_object = Qt; |
| 223 | 216 | ||
| 224 | /* Decide whether we need to add a directory separator. */ | 217 | /* Decide whether we need to add a directory separator. */ |
| 225 | if (directory_nbytes == 0 | 218 | bool needsep = (directory_nbytes == 0 |
| 226 | || !IS_ANY_SEP (SREF (directory, directory_nbytes - 1))) | 219 | || !IS_ANY_SEP (SREF (directory, directory_nbytes - 1))); |
| 227 | needsep = 1; | ||
| 228 | 220 | ||
| 229 | /* Windows users want case-insensitive wildcards. */ | 221 | /* Windows users want case-insensitive wildcards. */ |
| 230 | Lisp_Object case_table = | 222 | Lisp_Object case_table = Qnil; |
| 231 | #ifdef WINDOWSNT | 223 | #ifdef WINDOWSNT |
| 232 | BVAR (&buffer_defaults, case_canon_table) | 224 | case_table = BVAR (&buffer_defaults, case_canon_table); |
| 233 | #else | ||
| 234 | Qnil | ||
| 235 | #endif | 225 | #endif |
| 236 | ; | ||
| 237 | 226 | ||
| 238 | if (!NILP (match)) | 227 | /* Read directory entries and accumulate them into LIST. */ |
| 239 | CHECK_STRING (match); | 228 | Lisp_Object list = Qnil; |
| 240 | |||
| 241 | /* Loop reading directory entries. */ | ||
| 242 | for (struct dirent *dp; (dp = read_dirent (d, directory)); ) | 229 | for (struct dirent *dp; (dp = read_dirent (d, directory)); ) |
| 243 | { | 230 | { |
| 244 | ptrdiff_t len = dirent_namelen (dp); | 231 | ptrdiff_t len = dirent_namelen (dp); |
| 245 | Lisp_Object name = make_unibyte_string (dp->d_name, len); | 232 | Lisp_Object name = make_unibyte_string (dp->d_name, len); |
| 246 | Lisp_Object finalname = name; | 233 | Lisp_Object finalname = name; |
| 247 | 234 | ||
| 248 | /* Note: DECODE_FILE can GC; it should protect its argument, | 235 | /* This can GC. */ |
| 249 | though. */ | ||
| 250 | name = DECODE_FILE (name); | 236 | name = DECODE_FILE (name); |
| 251 | len = SBYTES (name); | ||
| 252 | 237 | ||
| 253 | /* Now that we have unwind_protect in place, we might as well | ||
| 254 | allow matching to be interrupted. */ | ||
| 255 | maybe_quit (); | 238 | maybe_quit (); |
| 256 | 239 | ||
| 257 | bool wanted = (NILP (match) || | 240 | if (!NILP (match) |
| 258 | fast_string_match_internal ( | 241 | && fast_string_match_internal (match, name, case_table) < 0) |
| 259 | match, name, case_table) >= 0); | 242 | continue; |
| 260 | 243 | ||
| 261 | if (wanted) | 244 | Lisp_Object fileattrs; |
| 245 | if (attrs) | ||
| 262 | { | 246 | { |
| 263 | if (!NILP (full)) | 247 | fileattrs = file_attributes (fd, dp->d_name, directory, name, |
| 264 | { | 248 | id_format); |
| 265 | Lisp_Object fullname; | 249 | if (NILP (fileattrs)) |
| 266 | ptrdiff_t nbytes = len + directory_nbytes + needsep; | 250 | continue; |
| 267 | ptrdiff_t nchars; | 251 | } |
| 268 | |||
| 269 | fullname = make_uninit_multibyte_string (nbytes, nbytes); | ||
| 270 | memcpy (SDATA (fullname), SDATA (directory), | ||
| 271 | directory_nbytes); | ||
| 272 | |||
| 273 | if (needsep) | ||
| 274 | SSET (fullname, directory_nbytes, DIRECTORY_SEP); | ||
| 275 | |||
| 276 | memcpy (SDATA (fullname) + directory_nbytes + needsep, | ||
| 277 | SDATA (name), len); | ||
| 278 | |||
| 279 | nchars = multibyte_chars_in_text (SDATA (fullname), nbytes); | ||
| 280 | |||
| 281 | /* Some bug somewhere. */ | ||
| 282 | if (nchars > nbytes) | ||
| 283 | emacs_abort (); | ||
| 284 | |||
| 285 | STRING_SET_CHARS (fullname, nchars); | ||
| 286 | if (nchars == nbytes) | ||
| 287 | STRING_SET_UNIBYTE (fullname); | ||
| 288 | |||
| 289 | finalname = fullname; | ||
| 290 | } | ||
| 291 | else | ||
| 292 | finalname = name; | ||
| 293 | 252 | ||
| 294 | if (attrs) | 253 | if (!NILP (full)) |
| 295 | { | 254 | { |
| 296 | Lisp_Object fileattrs | 255 | ptrdiff_t name_nbytes = SBYTES (name); |
| 297 | = file_attributes (fd, dp->d_name, directory, name, id_format); | 256 | ptrdiff_t nbytes = directory_nbytes + needsep + name_nbytes; |
| 298 | if (!NILP (fileattrs)) | 257 | ptrdiff_t nchars = SCHARS (directory) + needsep + SCHARS (name); |
| 299 | list = Fcons (Fcons (finalname, fileattrs), list); | 258 | finalname = make_uninit_multibyte_string (nchars, nbytes); |
| 300 | } | 259 | if (nchars == nbytes) |
| 301 | else | 260 | STRING_SET_UNIBYTE (finalname); |
| 302 | list = Fcons (finalname, list); | 261 | memcpy (SDATA (finalname), SDATA (directory), directory_nbytes); |
| 262 | if (needsep) | ||
| 263 | SSET (finalname, directory_nbytes, DIRECTORY_SEP); | ||
| 264 | memcpy (SDATA (finalname) + directory_nbytes + needsep, | ||
| 265 | SDATA (name), name_nbytes); | ||
| 303 | } | 266 | } |
| 267 | else | ||
| 268 | finalname = name; | ||
| 269 | |||
| 270 | list = Fcons (attrs ? Fcons (finalname, fileattrs) : finalname, list); | ||
| 304 | } | 271 | } |
| 305 | 272 | ||
| 306 | closedir (d); | 273 | closedir (d); |
| @@ -330,14 +297,14 @@ If MATCH is non-nil, mention only file names that match the regexp MATCH. | |||
| 330 | If NOSORT is non-nil, the list is not sorted--its order is unpredictable. | 297 | If NOSORT is non-nil, the list is not sorted--its order is unpredictable. |
| 331 | Otherwise, the list returned is sorted with `string-lessp'. | 298 | Otherwise, the list returned is sorted with `string-lessp'. |
| 332 | NOSORT is useful if you plan to sort the result yourself. */) | 299 | NOSORT is useful if you plan to sort the result yourself. */) |
| 333 | (Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort) | 300 | (Lisp_Object directory, Lisp_Object full, Lisp_Object match, |
| 301 | Lisp_Object nosort) | ||
| 334 | { | 302 | { |
| 335 | Lisp_Object handler; | ||
| 336 | directory = Fexpand_file_name (directory, Qnil); | 303 | directory = Fexpand_file_name (directory, Qnil); |
| 337 | 304 | ||
| 338 | /* If the file name has special constructs in it, | 305 | /* If the file name has special constructs in it, |
| 339 | call the corresponding file name handler. */ | 306 | call the corresponding file name handler. */ |
| 340 | handler = Ffind_file_name_handler (directory, Qdirectory_files); | 307 | Lisp_Object handler = Ffind_file_name_handler (directory, Qdirectory_files); |
| 341 | if (!NILP (handler)) | 308 | if (!NILP (handler)) |
| 342 | return call5 (handler, Qdirectory_files, directory, | 309 | return call5 (handler, Qdirectory_files, directory, |
| 343 | full, match, nosort); | 310 | full, match, nosort); |
| @@ -365,14 +332,15 @@ ID-FORMAT specifies the preferred format of attributes uid and gid, see | |||
| 365 | `file-attributes' for further documentation. | 332 | `file-attributes' for further documentation. |
| 366 | On MS-Windows, performance depends on `w32-get-true-file-attributes', | 333 | On MS-Windows, performance depends on `w32-get-true-file-attributes', |
| 367 | which see. */) | 334 | which see. */) |
| 368 | (Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort, Lisp_Object id_format) | 335 | (Lisp_Object directory, Lisp_Object full, Lisp_Object match, |
| 336 | Lisp_Object nosort, Lisp_Object id_format) | ||
| 369 | { | 337 | { |
| 370 | Lisp_Object handler; | ||
| 371 | directory = Fexpand_file_name (directory, Qnil); | 338 | directory = Fexpand_file_name (directory, Qnil); |
| 372 | 339 | ||
| 373 | /* If the file name has special constructs in it, | 340 | /* If the file name has special constructs in it, |
| 374 | call the corresponding file name handler. */ | 341 | call the corresponding file name handler. */ |
| 375 | handler = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes); | 342 | Lisp_Object handler |
| 343 | = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes); | ||
| 376 | if (!NILP (handler)) | 344 | if (!NILP (handler)) |
| 377 | return call6 (handler, Qdirectory_files_and_attributes, | 345 | return call6 (handler, Qdirectory_files_and_attributes, |
| 378 | directory, full, match, nosort, id_format); | 346 | directory, full, match, nosort, id_format); |
| @@ -1032,7 +1000,8 @@ file_attributes (int fd, char const *name, | |||
| 1032 | INT_TO_INTEGER (s.st_dev)); | 1000 | INT_TO_INTEGER (s.st_dev)); |
| 1033 | } | 1001 | } |
| 1034 | 1002 | ||
| 1035 | DEFUN ("file-attributes-lessp", Ffile_attributes_lessp, Sfile_attributes_lessp, 2, 2, 0, | 1003 | DEFUN ("file-attributes-lessp", Ffile_attributes_lessp, |
| 1004 | Sfile_attributes_lessp, 2, 2, 0, | ||
| 1036 | doc: /* Return t if first arg file attributes list is less than second. | 1005 | doc: /* Return t if first arg file attributes list is less than second. |
| 1037 | Comparison is in lexicographic order and case is significant. */) | 1006 | Comparison is in lexicographic order and case is significant. */) |
| 1038 | (Lisp_Object f1, Lisp_Object f2) | 1007 | (Lisp_Object f1, Lisp_Object f2) |